唯一/shared_ptr自定义操作符=

unique/shared_ptr with custom operator=

本文关键字:自定义 操作符 ptr shared 唯一      更新时间:2023-10-16

我正在使用一个多态类型(也就是说,我总是通过一个指针与它交互),它有方法"Destroy()"answers"Clone()",我想把它包装在一个资源安全的类型。

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

  1. 我在文档中错过了什么吗?有没有现成的方法来做到这一点?
  2. 如果没有,我应该扩展unique_ptr并覆盖复制操作吗?或者,我应该从头开始写我自己的资源句柄与所有通常的指针语义吗?

您可以围绕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;
};

使用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和浪费时间的最好方法是使它们在逻辑上不可能发生。如果需要做一些事情来销毁一个对象,这需要在析构函数中完成。如果需要做一些额外的事情来销毁从另一个对象克隆出来的对象,则该对象需要有一个内部标志,表明它是一个克隆对象,并让它的析构函数在此基础上做正确的事情。

一旦这样做了,你的代码就不可能因为忘记做一些事情来摆脱克隆对象而搞砸了。在将来,你可以庆幸自己不再浪费时间去寻找一堆现在永远不会产生的bug。未来的自己会感谢过去的自己。只要使用智能指针,因为他们打算被使用,并有clone()给你一个智能指针从一开始。