单身破坏的一个例子:失败的情况

时间:2016-01-13 05:47:56

标签: c++ static singleton destructor atexit

来自:https://sourcemaking.com/design_patterns/to_kill_a_singleton

  

有一件事是肯定的:如果是的话,你不能使用多个驱逐舰   单身破坏者彼此依赖。另一种方法是   完全避开驱逐舰,而是依靠草案标准   atexit()函数,正如Tim Peierls向我建议的那样:我坚持这一点   atexit()是一个很好的方法来清理C ++中的单例   希望单个实例具有程序生命周期而无需替换。

     

标准草案承诺很多:函数atexit()来自   用于指定在退出时调用的函数。如果是atexit()   调用时,实现不应该破坏初始化的对象   在atexit()调用之前,直到在指定的函数之后   atexit()调用已被调用。

     

我能看到失败的唯一方法是静态初始化   初始化析构函数依赖于Singleton实例的对象   在构造Singleton实例之后,即通过一些其他静态初始化。这表明类具有静态   实例应避免在破坏期间依赖单身人士。 (要么   至少应该有这样的类检查的方法   在破坏期间存在单身人士。)

我无法理解最后一段,即在哪种情况下会失败以及如何。

有人可以请点亮它。

1 个答案:

答案 0 :(得分:1)

由于这使用atexit而不是析构函数来清理单例,因此可以更改对象清理的顺序。例如:

Singleton S;
Object O;
// later in code:
Call atexit() to register cleanup function for S

通常,这些对象的销毁顺序为O,然后是S,但是添加了atexit调用后,这是相反的,因此在atexit调用中清除了S,然后O被销毁。如果O的析构函数以任何方式依赖于Singleton S,那么在析构函数运行时你将有未定义的行为。

避免这种情况的方法是在构造依赖它的任何对象之前调用atexit来注册Singleton清理函数。如果O本身就是一个静态对象,这可能很棘手,可能需要创建一个构造函数调用atexit的类,以便它可以插入到两个静态对象之间。

Singleton S;
struct SAtExit {
     SAtExit() { atexit(...); }
} SCleanup;
Object O;