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

Deleting dynamically allocated objects with private destructors

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

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

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

与访问任何其他私有成员函数一样,您必须在成员函数或友元函数中进行。一个例子:

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*/), {}};
    }
};

这是一个例子:

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();
}

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

因此,我假设您的对象管理自己的生命周期;例如,也许它维护了一个引用计数,然后当引用计数变为 0 时,在 release() 方法中调用 delete this。然后 "how to properly manage the object's lifetime" 问题的答案,作为 对象的用户,是"use the object properly",这样对象会在合适的时候释放自己。

例如,带有自定义删除器的 std::unique_ptr 可用于确保对象的 release() 在作用域退出时被调用,防止任何引用被泄漏。

就访问控制而言,提供删除功能是有效的,但会强制 class 的用户在所有地方使用自定义删除器。与标准默认删除器成为朋友更简洁:

struct Foo {
private:
    friend std::default_delete<Foo>;
    ~Foo() = default;
};

auto p = std::make_unique<Foo>(); // Works out of the box