明确删除析构函数而不调用delete

时间:2012-02-01 06:52:00

标签: c++ singleton c++11 destructor

我正在阅读C++11 FAQ并注意到这一点:

class X4 {
    ~X4() = delete; // Disallow destruction
}
     

这隐含地也禁止移动X4。允许复制,但已弃用。

我还找到了this quote

  

删除析构函数的定义将需要在free-store上进行分配,因为静态和自动对象隐式调用析构函数:`

struct C
{
    ~C()= delete; //prevent automatic and static objects
};
     

但是,这种技术没有它看起来那么有用,因为它也可以防止删除表达式。但是Singleton对象可以使用它。

哪个有道理。我的问题是,它是否被认为是一个具有明确删除的析构函数的Singleton的好习惯?此外,如果有人知道任何其他情况,您不应该致电delete,请告知我们。

3 个答案:

答案 0 :(得分:2)

实际上,您有时可能会发现自己处于破坏特定类型对象的安全状态。所以你要删除析构函数以防止任何人尝试。

对于Singleton,只有一个类型的实例,没有销毁它可能比没有清理的实例负载危害更小。

Singletons(或任何其他全局可用对象)的一个问题是您可能无法控制它们的依赖关系。然后很难找到一个安全的销毁顺序 - 如果全局数据库对象记录到您已安全关闭连接的全局记录器对象,但可选地,全局记录器对象通过全局数据库对象记录到数据库,那你就有问题了。

虽然你可以通过不破坏全局数据库对象来“解决”这个问题,但我认为这不应该被称为“良好实践”。这听起来更像是一种在没有重新设计的情况下处理糟糕情况的简单方法(尽管在我的例子中,重新设计也可能非常简单 - 只需确保DB记录器或数据库本身对日志消息执行一些有用的操作当连接关闭时。吞下它们,或者将它们重定向到另一个可用目的地。)

可能存在“好”的设计,其中特定类型的对象不能被破坏,但这不是C ++类设计的常用方式。

答案 1 :(得分:1)

  

另外,如果有人知道任何其他情况,你不应该打电话给删除,请告诉我。

使用内存池是我能想到的一种情况。

答案 2 :(得分:0)

有一种情况是永远不会调用析构函数,即使对于自动变量也是如此:当用户编写显式析构函数X时,类X::~X内的匿名联合的析构函数。由于联合是匿名的,因此X::~X无法调用它的析构函数(现在它不会如何来调用析构函数,因为它不知道是什么< / em>调用析构函数)。

顺便说一句,在这种情况下,用户无法声明要删除联合析构函数(再次缺少名称),但可以隐式删除。

奇怪的是,在这种情况下,默认析构函数X::~X会调用匿名联合的析构函数。但是,只要允许,这只是一个纯粹的形式问题,而析构函数调用没有任何效果。这是因为只有当联合的所有变体都具有琐碎的析构函数(因此联合本身也是如此)时才允许这样做;如果其中任何一个具有非平凡的析构函数,则会隐式删除union的析构函数,使X的默认析构函数无法运行(有效删除)。

然而,这并不意味着不能使用包含匿名联合的类X,其中至少有一个成员具有非平凡的析构函数。它只是意味着用户编写的X::~X必须直接破坏匿名联合的活动变体,绕过联合本身的已删除的析构函数。如果类包含允许知道哪个变体处于活动状态的其他成员,则这是可能的。类似X的构造函数应该直接构造union的最多一个变体,绕过匿名union的(可能已删除的)构造函数(除非变量是POD,这样的构造函数不应该直接分配给联盟的变体)。实际上,匿名联合的特殊成员函数是一种幻像实体,它不能是非常重要的,并且其唯一的作用是,可能被删除,以有效地将该已删除的状态传播到包含{{的相应特殊成员函数。 1}}。