私有析构函数

15

为什么我可以在自由存储区创建一个具有私有析构函数的类的对象,但不能在堆栈上创建?

例如,这是不合法的:

class Foo
{
public:
   explicit Foo( int );
   static void delete_foo(Foo* foo ) { delete foo; }
private:
   int x;
   ~Foo();
   Foo( const Foo& );
   Foo& operator=(const Foo& );
};

int main()
{
   Foo * fooptr = new Foo(5); // legal
   Foo::delete_foo( fooptr ); // legal 
   Foo foo(5); // illegal
}

能否请您提供一个简短的代码示例作为说明? - sharptooth
5个回答

19

当您在堆栈上创建时,必须在函数返回之前销毁它。如果假定相关函数无法访问析构函数,则不允许这样做。

当您在自由存储区上创建时,它留给其他代码来销毁,因为它们可以访问析构函数。

具有私有析构函数的类的成员函数可以在堆栈上创建实例。静态成员函数甚至可以在没有预先存在的实例的情况下调用。尽管如此,可能没有好的理由编写这样的代码。


1
@Potatoswatter:通过“友元”代理强制用户访问对象可能是有用的。不过似乎有限。 - Matthieu M.
1
@Matthieu:是的,我应该提到这一点。编写私有析构函数有很好的理由。我只是想说,很少会有静态成员函数创建临时实例,或者这样的对象根本不会被放置在堆栈上。 - Potatoswatter
唯一的例外当然是常见的单例实现:static Singelton& instance(); /*...*/ Singleton& Singleton::instance() { static theInstance; return theInstance; } - MSalters
@MSalters:呃,呃,呃,呃,呃,呃,呃。 - GManNickG
1
@Potatoswatter:尽管如此,它的析构函数仍然会被调用 :) - Matthieu M.

10

由于具有 自动存储 的对象需要被自动销毁,因此析构函数需要可用于调用;如果不可用,则无法将该类型放在自动存储中。

相反,当您动态分配它时,您需要删除它。 当然,您也可以选择不这样做。

*在“典型”的平台上,这里的对象通常在堆栈上分配。


2

在自由存储区创建对象不需要公共析构函数,但在堆栈中创建对象需要,因为对象将在超出范围时被销毁。您可以在自由存储区创建对象,但不能删除它,所以除非对象或友元函数销毁它,否则会导致内存泄漏。


2
您只能在可以访问析构函数的范围内在堆栈上创建一个对象。因此,您可以在类的友元函数、静态成员函数(甚至是普通类成员)中这样做。
对于局部变量,函数结束时会自动删除它们,因此必须能够隐式地调用析构函数。
如果您具有适当的构造函数,则可以从任何地方使用 new 创建对象。
如果您将其用作智能指针,则必须确保它所在的位置拥有删除的权限。这可能因不同的智能指针而异,并且对于某些智能指针,您可以提供自定义析构函数,该函数可以是类的静态成员。

0
因为这样您就可以强制将对象动态地分配,即使用 new 运算符。要使其正常工作,您需要实现一个 dispose() 方法,在返回之前调用 "delete this"。这使得可以创建 finalizing 方法,在对象或对象的一部分被销毁之前调用它们,因此可以安全地删除或断开实例成员,以防虚拟析构函数链被调用。

这更像是对另一个问题的回答,关于私有析构函数的用途,而不是OP在这里所问的,即为什么机械地私有析构函数会防止自动实例化。 - underscore_d
是的,得到最多赞的答案提供了答案,我确实是从“为什么需要那个?”的角度来看待它的。 - Valery Arkhangorodsky

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