私有析构函数的作用是什么?

226

私有析构函数的作用是什么?

9个回答

204

基本上,当您希望其他类负责管理您的类的对象生命周期,或者有理由防止对象被销毁时,您可以将析构函数设为私有。

例如,如果您正在进行一些引用计数的操作,可以让对象(或已"friend"授权的管理器)负责计算对它自己的引用次数,并在引用计数归零时删除它。私有析构函数将防止其他人在仍存在对该对象的引用时将其删除。

另一个例子,如果您有一个对象,它具有可能由程序中的其他条件决定是否由管理器(或其本身)销毁它或拒绝销毁它的情况,比如数据库连接处于打开状态或文件正在被写入。您可以在类或管理器中设置一个"request_delete"方法,它将检查并根据情况删除或拒绝,并返回一个状态来告诉您它所做的事情。这比简单地调用"delete"更加灵活。


我希望示例能够同时出现在文章中的两种情况。新手无法直接想象这样的场景。 - justanotherguy

91

这样的对象永远不能在栈上创建,只能在堆上创建。删除操作必须通过友元或成员函数来执行。一个产品可能会使用单个对象层次结构和自定义内存管理器——这些情况下可能需要使用私有析构函数。

#include <iostream>
class a {
    ~a() {}
    friend void delete_a(a* p);
};


void delete_a(a* p)  {
    delete p;
}

int main()
{
    a *p = new a;
    delete_a(p);

    return 0;
}

34
更正:这样的对象可以在栈上创建(但只能在友元或自身的作用域内)。 - Thomas Eding
1
此外,在托管实现中,它不能是静态或全局对象(即具有“静态存储期”),因为析构函数将在程序退出时被调用。 - Peter - Reinstate Monica
4
修正2:可以使用就地 new 在栈上创建这样的对象。 - DexterHaxxor
1
与堆栈无关。在堆上创建和销毁它的相同方法也可以在堆栈上使用。 - Jimmy T.

46

URL已经过时。我会将其更新为https://learn.microsoft.com/en-us/archive/blogs/larryosterman/private-destructors,但编辑队列已满。如果有其他人看到,请尝试进行编辑! - undefined

18

COM使用这种策略来删除实例。COM将析构函数设置为私有,并提供一个接口来删除该实例。

下面是一个释放方法的示例。

int MyRefCountedObject::Release() 
{
 _refCount--;
 if ( 0 == _refCount ) 
 {
    delete this;
    return 0;
 }
 return _refCount;
}

ATL COM对象是这种模式的一个典型例子。


13

除了已经存在的答案之外,私有构造函数和析构函数在实现需要将创建的对象分配到堆上的工厂时非常有用。一般情况下,对象会由静态成员或友元创建/删除。以下是典型用法示例:

class myclass
{
public:
    static myclass* create(/* args */)  // Factory
    {
        return new myclass(/* args */);
    }

    static void destroy(myclass* ptr)
    {
        delete ptr;
    }
private:
    myclass(/* args */) { ... }         // Private CTOR and DTOR
    ~myclass() { ... }                  // 
}

int main ()
{
    myclass m;                          // error: ctor and dtor are private
    myclass* mp = new myclass (..);     // error: private ctor
    myclass* mp = myclass::create(..);  // OK
    delete mp;                          // error: private dtor
    myclass::destroy(mp);               // OK
}

7

该类只能被自身删除。如果您正在创建某种引用计数对象,则仅释放方法可以删除对象,从而可能帮助您避免错误。


3

dirkgently是错误的。这里有一个示例,展示了在堆栈上创建具有私有构造函数和析构函数的对象(我在这里使用静态成员函数,但也可以使用友元函数或友元类来实现)。

#include <iostream>

class PrivateCD
{
private:
    PrivateCD(int i) : _i(i) {};
    ~PrivateCD(){};
    int _i;
public:
    static void TryMe(int i)
    {
        PrivateCD p(i);
        cout << "inside PrivateCD::TryMe, p._i = " << p._i << endl;
    };
};

int main()
{
    PrivateCD::TryMe(8);
};

这段代码将会输出: 在 PrivateCD::TryMe 内部,p._i = 8。

6
我很确定dirkgently的意思是使用你的类的代码不能在堆栈上实例化该类。当然,在类方法中仍然可以在堆栈上实例化该类,因为在那种情况下,您可以访问私有成员。 - Edward Loper

3

我知道你在问私有析构函数。下面是我使用受保护的析构函数的方法。这个想法是你不想通过指向添加额外功能的类的指针来删除主类。
在下面的示例中,我不希望通过HandlerHolder指针删除GuiWindow。

class Handler
{
public:
    virtual void onClose() = 0;
protected:
    virtual ~Handler();
};

class HandlerHolder
{
public:
    void setHandler( Handler* );
    Handler* getHandler() const;
protected:
    ~HandlerHolder(){}
private:
    Handler* handler_;
};

class GuiWindow : public HandlerHolder
{
public:
    void finish()
    {
        getHandler()->onClose();
    }

    virtual ~GuiWindow(){}
};

2

这可能是解决Windows中每个模块可以使用不同堆栈的问题的一种方法,例如Debug堆栈。如果没有正确处理该问题,会发生糟糕的事情


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接