自动克隆unique_ptr

时间:2014-05-18 19:55:05

标签: c++ c++11 clone copy-constructor unique-ptr

std::unique_ptr有一个已删除的复制构造函数,这意味着如果您的类unique_ptr中有Foo作为数据成员,那么您必须为{{1}编写自己的复制构造函数并手动深层复制该成员(即使编译器生成的复制构造函数适用于所有其他成员)。

为了能够以多态方式进行复制,可以使用Foo方法模式。假设我们的对象有一个像这样的克隆方法:

clone()

Foo现在看起来像这样:

class Base {
    virtual std::unique_ptr<Base> clone() = 0;
};

现在,我找到了一种自动克隆class Foo { public: ... Foo(Foo const& other) : b(other.b->clone()) , // init 10 more members that could otherwise be auto-copied just fine // with the automatically generated copy constructor {} ... private: std::unique_ptr<Base> b; //10 more data members }; 的方法,方法是在Foo::b上编写一个包装器,通过调用unique_ptr定义复制构造函数和赋值。

clone

现在,如果我们使用它,我们不需要定义我们自己的复制构造函数:

template <typename T>
class auto_cloned_unique_ptr
{
private:
    std::unique_ptr<T> up;

public:
    // copy constructor
    auto_cloned_unique_ptr(auto_cloned_unique_ptr<T> const& other)
        : up(other.up->clone()) {}

    // copy assignment
    auto_cloned_unique_ptr<T>& operator =(auto_cloned_unique_ptr<T> const& other)
    {
        this->up = other.up->clone();
        return *this;
    }

    auto_cloned_unique_ptr(std::unique_ptr<T> _up)
        : up(std::move(_up)) {}

    // Delegate everything else to unique_ptr
    auto_cloned_unique_ptr(auto_cloned_unique_ptr<T>&& other)
        : up(std::move(other.up)) {}

    auto_cloned_unique_ptr<T>& operator =(auto_cloned_unique_ptr<T>&& other)
    {
        this->up = std::move(other.up);
        return *this;
    }

    auto operator *() const {return *up;}
    auto operator->() const {return up.operator->();}
    auto get() -> const {return up.get();}

};

这种方法是否非常不受欢迎(在class Foo2 { public: ... private: auto_cloned_unique_ptr<Base> b; //10 more data members }; 上使用非标准包装器)?

3 个答案:

答案 0 :(得分:1)

您的方法存在的问题是它正在改变unique_ptr的含义。 unique_ptr的关键在于它告诉谁是对象的所有者。如果为unique_ptr添加一个拷贝构造函数,那意味着什么?你在复制所有权吗? A和B都是唯一拥有的东西?那没有意义。如果他们共享所有权,那么您应该使用shared_ptr来指示共享所有权。如果您想拥有该对象副本的唯一所有者,您自然会通过make_unique(* pFoo)表示。使用基础对象和派生对象,使基础对象具有
    virtual unique_ptr&lt; Foo&gt;克隆()const = 0;
是一个完全正常的结构。也就是说,派生类知道如何复制自己,因此它们不会生成切片副本,但是它们会将unique_ptr返回给基类,以指示您将拥有它们生成的副本。在这些克隆操作中,是的,您将需要显式处理派生类的不可复制成员,因此您无法使用默认或生成的复制构造函数。您需要回答&#34;复制包含无法复制的内容的内容是什么意思?&#34;
作为一个具体的例子,复制具有互斥锁的派生类意味着什么?如果它被锁定而另一个线程正在等待它怎么办?看看为什么很难给出一般答案?

答案 1 :(得分:0)

这种方法很好,但是当你不打算这样做时,你应该非常小心不要克隆你的对象。

同样从unique_ptr继承可能会提高性能

答案 2 :(得分:0)

首先让我解释一下您想做什么:您希望Foo的每个实例在Base中都有自己的b实例;特别是,如果您复制Foo,则该副本将具有自己的新Base,最初带有相同的“值”。换句话说,Base的行为应类似于 value

同时,您不能将Base直接存储在Foo中,因为它是一个抽象类。换句话说,您希望b成为polymorphic

有了它:您想要一个多态值。其他人已经意识到了这种需求,并建议将C ++ 20命名为polymorphic_value<Base>。从文档中:

  

类模板polymorphic_value赋予类似值的语义   一个免费存储的分配对象。 polymorphic_value可以包含一个   从T公开派生的类的对象,并复制   polymorphic_value将复制派生类型的对象。

它具有一个参考实现,您现在可以使用它。简而言之,它是std::unique_ptr的包装,类似于您的建议。