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
};
上使用非标准包装器)?
答案 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
的包装,类似于您的建议。