我喜欢 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'
这让我感到困惑。是否存在变通方法?
答案 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)