choeger choeger - 2 months ago 11
C++ Question

Why not to copy a class consisting of a single shared_ptr

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?

Answer

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.