为什么不复制一个包含单个shared_ptr的类

时间:2016-09-23 10:44:15

标签: c++ copy move shared-ptr

最近,我阅读了an article关于C ++中的惰性数据结构(这个问题不是关于懒惰,或者是特定的数据结构,但这只是动机)。

延迟流(列表)实现如下:

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();
    }
};

作者提到了移动构造函数:

  

我还添加了移动构造函数和移动赋值运算符以提高效率。

但是,由于明确存在,人们不能简单地指定Stream。这背后的动机是什么?

据我所知,该课程仅由shared_ptr组成,可以轻易复制。在这样的班级中禁止复制构造有什么好处吗?

2 个答案:

答案 0 :(得分:1)

function fncSubCheck() { //Use this instead of document.ready to make sure it will run when needed $(document).off('click', '.obj-check'); $(document).on('click', '.obj-check', function (e) { //Check if checkbox is check and check all items below it var blIsCheck = $(this).is(':checked'); if (blIsCheck) { var objNext = $(this).parent().parent().nextAll().find('.obj-check'); $(objNext).prop('checked', blIsCheck); } else { //Will uncheck all items above it var objPrev = $(this).parent().parent().prevAll().find('.obj-check'); $(objPrev).prop('checked', blIsCheck); } }); } 在内部用于共享延迟值单元格,作为私有实现的一部分。

但是,从用户的角度来看,它是一个不可变的对象。提供复制构造函数和赋值运算符可以撤消这种不变性。

他正在模拟Haskell的不可变对象的行为。

如果它是线程安全的,那么使这个对象可以复制是合理的,因为实际上它是一个(尽管比通常更复杂)共享impl的句柄。

但是,复制者需要了解他们正在将句柄复制到共享状态,而不是自己说明。

答案 1 :(得分:1)

我认为这是一种过早优化。

首先,由于三/五(http://en.cppreference.com/w/cpp/language/rule_of_three)的规则,移动复制/赋值构造函数将以相同的方式创建,而无需输入。

因此,唯一的区别是,正如您已经指出的那样,缺少副本/分配构造函数。最好将它们标记为已删除,例如:

 Stream(Stream & stm) = deleted;

然而,这里真正的问题是使用只有一个所有者的共享指针。使用std::unique_ptr会好得多。随着它的使用,副本和赋值被自动禁用,作者的意图更加清晰。