0

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

有一件事是肯定的:如果单例析构函数相互依赖,则不能使用多个析构函数。另一种方法是完全避开驱逐舰,而是依赖标准草案 atexit() 函数,正如 Tim Peierls 向我建议的那样:我认为 atexit() 是在 C++ 中清理单例的好方法,当你真的想要单例程序时终生且不可更换。

标准草案有很多承诺:函数 atexit() 可用于指定要在退出时调用的函数。如果要调用 atexit(),则在 atexit() 调用中指定的函数被调用之前,实现不应销毁在 atexit() 调用之前初始化的对象。

我可以看到这种失败的唯一方法是,如果在构造 Singleton 实例之后初始化其析构函数依赖于 Singleton 实例的静态初始化对象 ,即通过其他一些静态初始化。这表明具有静态实例的类在销毁期间应避免依赖单例。(或者至少应该有一种方法让此类类在销毁期间检查单例是否存在。)

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

有人可以说明一下吗。

4

1 回答 1

1

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

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

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

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

Singleton S;
struct SAtExit {
     SAtExit() { atexit(...); }
} SCleanup;
Object O;
于 2016-01-13T06:19:10.793 回答