Search code examples
c++copymoveshared-ptr

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?


Solution

  • 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.