来自:https://sourcemaking.com/design_patterns/to_kill_a_singleton
有一件事是肯定的:如果是的话,你不能使用多个驱逐舰 单身破坏者彼此依赖。另一种方法是 完全避开驱逐舰,而是依靠草案标准 atexit()函数,正如Tim Peierls向我建议的那样:我坚持这一点 atexit()是一个很好的方法来清理C ++中的单例 希望单个实例具有程序生命周期而无需替换。
标准草案承诺很多:函数atexit()来自 用于指定在退出时调用的函数。如果是atexit() 调用时,实现不应该破坏初始化的对象 在atexit()调用之前,直到在指定的函数之后 atexit()调用已被调用。
我能看到失败的唯一方法是静态初始化 初始化析构函数依赖于Singleton实例的对象 在构造Singleton实例之后,即通过一些其他静态初始化。这表明类具有静态 实例应避免在破坏期间依赖单身人士。 (要么 至少应该有这样的类检查的方法 在破坏期间存在单身人士。)
我无法理解最后一段,即在哪种情况下会失败以及如何。
有人可以请点亮它。
答案 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;