Auto-cloning unique_ptr
Auto-cloning unique_ptr
std::unique_ptr
有一个删除的复制构造函数,这意味着如果你在Foo
类中有一个unique_ptr
作为数据成员,那么你必须为Foo
编写自己的复制构造函数并手动深度复制该成员(即使编译器生成的复制构造函数对所有其他成员都很好)。
为了能够以多态方式复制,可以使用clone()
方法模式。假设我们的对象有如下的克隆方法:
class Base {
virtual std::unique_ptr<Base> clone() = 0;
};
Foo现在看起来是这样的:
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
};
这样的方法是非常不赞成的(在unique_ptr
上使用非标准包装器)吗?
让我先解释一下你想做什么:你想让Foo
的每个实例在b
中有自己的Base
实例;特别是,如果复制一个Foo
,该副本将有它自己的新Base
,最初具有相同的"值"。换句话说,Base
应该像一个值。
同时,你不能将Base
直接存储在Foo
中,因为它是一个抽象类。换句话说,您希望b
成为polymorphic
。
你知道了:你想要一个多态值。其他人已经认识到这一需求,并将c++ 20命名为polymorphic_value<Base>
。来自文档:
类模板,polymorphic_value,赋予类似值的语义自由存储分配的对象。一个多态值可以保存一个从T公开派生的类的多态值将复制派生类型的对象。
它有一个你现在可以使用的参考实现。简单地说,它是一个围绕std::unique_ptr
的包装器,类似于您所建议的。
您的方法的问题在于它正在改变unique_ptr的含义。unique_ptr的关键在于它告诉谁是对象的所有者。如果为unique_ptr添加复制构造函数,这意味着什么?你是否在复制所有权?A和B都唯一地拥有这个东西?这没有道理。如果它们共享所有权,那么您应该使用shared_ptr来指示共享所有权。如果您想要对象副本的唯一所有者,您自然会通过make_unique(*pFoo)来表示。对于基类和派生类对象,让基类对象具有
virtual unique_ptr
是一个非常正常的结构。也就是说,派生类知道如何复制它们自己,所以它们不生成切片副本,但是它们向基类返回一个unique_ptr,以表明您将拥有它们生成的副本。在这些克隆操作中,是的,您需要显式地处理派生类的不可复制成员,因此您不能只使用默认的或生成的复制构造函数。你需要回答"复制包含不可复制内容的东西是什么意思"
作为一个具体的例子,复制具有互斥锁的派生类意味着什么?如果它被锁定,而另一个线程正在等待它呢?明白为什么很难给出一个笼统的答案了吧?
这种方法很好,但是您应该非常小心,不要在不打算克隆对象的情况下克隆对象。
继承unique_ptr也可以提高性能
- 为什么 std::unique 不调用 std::sort?
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 生成"unique"矩阵
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 我对 std::unique(算法)C++有问题
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- std::shared_ptr::unique(),复制和线程安全
- 如何在C++03中用自定义谓词调用std::unique
- C++中的指针否定 (!ptr == NULL)
- C++14 unique_ptr并使用已删除的函数'std::unique-ptr' unique_ptr错误