C++ 11 - 复制指向抽象类型的智能指针的构造?

Hel*_*irr 1 c++ copy-constructor unique-ptr copy-assignment c++11

我喜欢std :: unique_ptr.它帮助我防止内存泄漏,这是非常有用的.但是有一个问题:不允许复制分配和构造.

即使这种限制有助于程序员的安全,但它也是非常有限的.如果使用std :: unique_ptr作为其成员使用复制赋值和构造的类,则最终会出现问题.这就是为什么我使用复制构造和赋值创建了我自己的unique_ptr包装器.这是它的复制构造函数:

template<typename T, class Deleter>
PointerSmartSafe<T, Deleter>::PointerSmartSafe(PointerSmartSafe const& pointer_smart_safe_) noexcept : _m_opPointerUnique((_m_opPointerUnique == nullptr) ? new T(*_m_opPointerUnique.get()) : nullptr){

}
Run Code Online (Sandbox Code Playgroud)

这是复制赋值运算符:

template<typename T, class Deleter>
PointerSmartSafe<T, Deleter>& PointerSmartSafe<T, Deleter>::operator=(PointerSmartSafe const& pointer_smart_safe_) noexcept{
    _m_opPointerUnique = decltype(_m_opPointerUnique)(new T(*_m_opPointerUnique.get()));
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

一切正常,直到我最终使用抽象基类作为类型(T).我收到如下错误消息:

error: cannot allocate an object of abstract type 'AbstractBaseClass'
Run Code Online (Sandbox Code Playgroud)

这让我感到困惑.是否存在变通方法?

Jon*_*ely 7

但是有一个问题:不允许复制分配和构造.

那不是问题.如果你发现它有问题,你就会做错事.

即使这种限制有助于程序员的安全,但它也是非常有限的.

这是有意限制的,也许你应该重新考虑你的设计.

这就是为什么我使用复制构造和赋值创建了我自己的unique_ptr包装器.

你想要的不是unique_ptr当时的,你想要一个"克隆ptr"

这让我感到困惑

有什么令人困惑的?您正在尝试创建抽象基类的实例.您的代码也会对非抽象基础进行切片.这本质上是不安全的.

这应该告诉你一些重要的事情:复制a所持有的对象unique_ptr不能一般地完成,它需要没有的上下文unique_ptr.该上下文要么必须来自拥有您想要复制的东西的对象(这需要拥有对象知道对象的动态类型),要么来自您想要复制的东西(可以使用虚函数来复制)正确动态类型的上下文.)

传统的解决方案是为clone()您的类型添加虚拟成员函数,然后尽可能使用它.

您可以将其合并到您的构造函数中,如下所示:

template<typename T>
  auto clone(T* t) -> decltype(t->clone())
  { return t->clone(); }

template<typename T>
  std::unique_ptr<T> clone(T* t, ...)
  { return std::unique_ptr<T>(new T(*t)); }

// ... 

_m_opPointerUnique((_m_opPointerUnique == nullptr) ? clone(_m_opPointerUnique.get()) : nullptr)
Run Code Online (Sandbox Code Playgroud)

  • @Helixirr我写了一个名为`value_ptr`(它模仿指针上的值语义).你想要实现移动和复制.我检测到存在`T() - > Clone()const`和`T() - > clone()const`方法,以及免费`Clone(T const*)`和`clone(T const*) `函数,默认`克隆(T const*)`只对`T`有效,可以复制构造(通过traits)并执行`new T(*t)`.哦,当`U`是`T`的子类,或者甚至可以复制构造时,不要忘记支持`value_ptr <U> = value_ptr <T>` (2认同)