Recently, I read an article about lazy data structures in C++ (this question is not about lazy, or the particular data structure, though - it is just the motivation).
A lazy stream (list) is implemented as follows:
template<class T>
class Stream
{
private:
std::shared_ptr <Susp<Cell<T>>> _lazyCell;
public:
Stream() {}
Stream(std::function<Cell<T>()> f)
: _lazyCell(std::make_shared<Susp<Cell<T>>>(f))
{}
Stream(Stream && stm)
: _lazyCell(std::move(stm._lazyCell))
{}
Stream & operator=(Stream && stm)
{
_lazyCell = std::move(stm._lazyCell);
return *this;
}
bool isEmpty() const
{
return !_lazyCell;
}
T get() const
{
return _lazyCell->get().val();
}
Stream<T> pop_front() const
{
return _lazyCell->get().pop_front();
}
};
The author mentions the move constructor:
I also added a move constructor and a move assignment operator for efficiency.
However, due to the explicit presence, one cannot simply assign a Stream
. What is the motivation behind this?
As far as I can tell, the class consists solely of a shared_ptr
, which can be trivially copied. Is there any benefit in forbidding copy-construction in such a class?
The shared_ptr
is used internally to share lazy value cells as part of the private implementation.
However, from the user's point of view, it's an immutable object. Providing a copy constructor and assignment operator would undo this immutability.
He is modelling Haskell's immutable object's behaviour.
If it were thread-safe to do so, it would be reasonable to make this object copyable since in reality it's a handle to an (albeit more complex than usual) shared impl.
However, copyers would need to understand that they were copying a handle to shared state, and not state itself.