2016-09-23 87 views
1

我正在使用具有方法“Destroy()”和“Clone()”的多态类型(即,我总是通过指针与它交互),并且我想以资源安全类型包装它。unique/shared_ptr自定义运算符=

现在,如果“Destroy()”是所有我必须担心的,那么我可以使用unique_ptr与自定义删除器,这将很容易。 但是,此资源句柄类型被用作另一种类型的成员,否则这种类型可以使用默认生成的副本和分配操作进行复制。理想情况下,我想定制资源句柄的拷贝构造函数和赋值来调用“Clone()”,就像我已经自定义资源句柄的析构函数来调用“Destroy()”一样。但是通过unique_ptr和shared_ptr上的文档查看,我没有看到任何会让我这样做的东西。

  1. 我错过了文档中的内容吗?有没有现成的标准方法来做到这一点?
  2. 如果不是,我应该扩展unique_ptr并覆盖复制操作吗?
  3. 或者,我是否应该从头开始编写自己的资源句柄和所有常用的指针语义?
+2

encapsulate unique_ptr。 –

+3

将'unique_ptr '换成某种类型,并为其执行移动和复制操作。这些动作可以默认,复制会调用'克隆'。 – Praetorian

+0

我怀疑你真的不想调用'Clone()',除非你想结束两个不同的由两个独立的智能指针管理的类型的对象。 – Galik

回答

3

您可以创建包装器std::unique_ptr

// To handle your cusstom Destroy 
struct DestroyDeleter 
{ 
    void operator(Interface* o) { 
     object->Destroy(); 
     delete object; 
    } 
}; 

using InterfacePtr = std::unique_ptr<Interface, DestroyDeleter>; 

// To handle the copy with clone: 
class wrapper 
{ 
public: 
    explicit wrapper(InterfacePtr o) : data(std::move(o)) {} 

    wrapper(const wrapper& rhs) : data(rhs.data->Clone()) {} 
    wrapper(wrapper&& rhs) = default; 

    wrapper& operator =(const wrapper& rhs) { data = rhs.data->Clone(); } 
    wrapper& operator =(wrapper&& rhs) = default; 

    const Interface* operator ->() const { return data.get(); } 
    Interface* operator ->() { return data.get(); } 

    const Interface& operator *() const { return data; } 
    Interface& operator *() { return *data; } 

private: 
    InterfacePtr data; 
}; 
0

的原因之一,对于具有unique_ptrshared_ptr是复制和周围杂耍这些指针是一种廉价的操作,并不涉及复制基础对象。

这就是为什么智能指针不能实现任何手段来安装您自己的operator=。正如我理解你的问题,当智能指针被复制时,你想要调用自定义的Clone()Destroy()方法。

那么,unique_ptrshared_ptr执行自己operator=这是正确的事情。

对于初学者来说,无论你的Destroy()是做什么都应该在你的类的析构函数中完成。这是一个析构函数。然后,您的clone()方法只需要克隆自己的对象,并返回一个新的unique_ptr,因此,当您已经有一个现有的unique_ptrshared_ptr时,使用它调用clone()方法克隆该对象并返回一个智能指针指向克隆对象:

std::unique_ptr<myClass> p; // Or std::shared_ptr 

// p is initialized, populated from there. 

std::unique_ptr<myClass> new_p=p->clone(); 

具有独特Destroy()方法必须销毁的对象之前被调用是产卵的错误无尽的游行的邀请。在销毁克隆对象时忘记调用它只是一个时间问题。

避免用代码中的错误创建和浪费时间的最佳方法是使它们在逻辑上不可能发生。如果为了销毁一个对象需要做些什么,这需要在析构函数中完成。如果为了销毁从另一个对象克隆的对象需要做一些额外的工作,对象需要有一个内部标志来指示它是一个克隆对象,并且它的析构函数根据这个标准来做正确的事情。

一旦完成,通过忘记做某件事来摆脱克隆的对象,将会使代码变得逻辑上不可行。您可以祝贺自己在未来拯救自己,免得浪费时间寻找一堆现在永远不会创建的bug。你未来的自我会感谢你的过去的自我。只需使用智能指针就可以使用,并且从一开始就有clone()为您提供智能指针。

+0

'>对于初学者,你的Destroy()所做的任何事情都应该在你的类的析构函数中完成。这是一个析构函数。 ...在破坏对象之前必须调用一个独特的Destroy()方法是一个邀请产生无尽的错误游行。' 我同意所有这一切。但这不是我的课。我只是不得不使用它的悲伤熊猫。使这个资源句柄包装的重点是让这个容易出错的类更安全。 –

+0

你可以继承它,并在这个坏事上做得更好吗? –