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

时间:2013-03-27 12:55:27

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

我喜欢 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){

}

这是复制赋值运算符:

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

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

error: cannot allocate an object of abstract type 'AbstractBaseClass'

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

1 个答案:

答案 0 :(得分:7)

  

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

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

  

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

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

  

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

你想要的不是unique_ptr那么,你想要一个“克隆ptr”

  

这让我感到困惑

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

这应该告诉你重要的事情:复制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)