使用私有析构函数删除动态分配的对象

Deleting dynamically allocated objects with private destructors

本文关键字:动态分配 对象 删除 析构函数      更新时间:2023-10-16

所以我遇到了一个代码片段,它表明如果我们想要强制动态分配任何类对象,我们应该将其析构函数设为私有

我试过了,是的,它不允许在堆栈上实例化对象。但是当我实例化一个动态分配的实例并尝试删除对象(否则会导致泄漏(时 - 我一直收到关于析构函数是私有的警告。

如何正确管理具有私有析构函数的动态分配对象的内存?

与访问任何其他私有成员函数一样,您必须在成员或好友函数中执行此操作。举个例子:

class foo {
~foo(){}
public:
static void del(const foo* ptr)
{
delete ptr;
}
};

或者更好的是,强制客户端使用智能指针:

class foo {
~foo(){}
struct deleter {
void operator()(const foo* ptr)
{
delete ptr;
}
};
public:
static std::unique_ptr<foo, deleter> make(/*args*/)
{
return {new foo(/*args*/), {}};
}
};

提供删除函数就访问控制而言是有效的,但会强制类的用户在任何地方使用自定义删除器。与标准的默认删除器交朋友更简洁:

struct Foo {
private:
friend std::default_delete<Foo>;
~Foo() = default;
};
auto p = std::make_unique<Foo>(); // Works out of the box

强制动态分配对象的唯一好理由是它需要以某种方式管理自己的生存期。否则,创建对象的代码负责管理其生存期---并且由于自动存储持续时间是一种有效的生存期管理策略,因此不应有意禁用它。

因此,我假设您的对象管理自己的生存期;例如,也许它维护一个引用计数,然后在引用计数变为 0 时在release()方法中调用delete this。那么"如何正确管理对象的生存期"这个问题的答案,作为对象的用户,就是"正确使用对象",这样对象就会在时机成熟时自行释放。

例如,具有自定义删除程序的std::unique_ptr可用于确保在范围退出时调用对象的release(),从而防止任何引用泄露。

下面是一个例子:

class Example {
public:
void kill_me() { // a public function
delete this; // is allowed to delete
}
private:
~Example() {}    // private destructor
};
int main() {
Example* e = new Example;
e->kill_me();
}