1

我喜欢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'

这让我很困惑。是否存在解决方法?

4

1 回答 1

7

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

那不是问题。如果你发现它有问题,那么你做错了什么。

尽管这个限制有助于程序员的安全,但它也是相当有限的。

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

这就是为什么我使用复制构造和分配围绕 unique_ptr 创建了自己的包装器。

你想要的不是一个unique_ptrthen,你想要一个“克隆 ptr”

这让我很困惑

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

这应该告诉您一些重要的事情:复制 a 持有的对象unique_ptr通常无法完成,它需要 a 没有的上下文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)
于 2013-03-27T13:07:44.840 回答