如果析构函数有副作用并且对象是从另一个静态对象的析构函数访问的,如何进行静态反初始化?

Tob*_*ias 4 c++ destructor initialization-order static-initialization

有一个简单且众所周知的模式可以避免静态初始化失败,在C++ FAQ Lite 的第 10.13 节中进行了描述。

在这个标准模式中,有一个权衡是构造的对象永远不会被破坏(如果析构函数没有重要的副作用,这不是问题)或者不能从另一个静态对象的析构函数安全地访问静态对象(请参阅C++ FAQ Lite 的 10.14 节)。

所以我的问题是:如果静态对象的析构函数具有最终必须发生的重要副作用并且静态对象必须由另一个静态对象的析构函数访问,那么您如何避免静态反初始化失败?


(注意:FAQ-lite 提到这个问题在C++ FAQs: FAQs 16.17 of C++ FAQs: FAQs by M. Cline and and and G. Lomow 中得到了回答。我无权阅读这本书,这就是我问这个问题的原因。 )

Mar*_*ork 5

函数静态对象(如全局对象)保证会被销毁(假设它们已创建)。

毁灭的顺序是创造的逆序。
因此,如果一个对象在销毁期间依赖于另一个对象,您必须保证它仍然可用。这相对简单,因为您可以通过确保正确完成创建顺序来强制销毁顺序。

以下链接是关于单例的,但描述了类似的情况及其解决方案:
寻找 C++ 静态初始化顺序问题

推断到 FAQ lite 中描述的惰性初始化全局变量的一般情况,我们可以解决这样的问题:

namespace B
{
    class B { ... };

    B& getInstance_Bglob;
    {
        static B instance_Bglob;
        return instance_Bglob;;
    }

    B::~B()
    {
         A::getInstance_abc().doSomthing();
         // The object abc is accessed from the destructor.
         // Potential problem.
         // You must guarantee that abc is destroyed after this object.
         // To gurantee this you must make sure it is constructed first.
         // To do this just access the object from the constructor.
    }

    B::B()
    {
        A::getInstance_abc();
        // abc is now fully constructed.
        // This means it was constructed before this object.
        // This means it will be destroyed after this object.
        // This means it is safe to use from the destructor.
    }
}
namespace A
{
    class A { ... };

    A& getInstance_abc()
    {
        static A instance_abc;
        return instance_abc;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Caspin:在当前标准“ISO/IEC 14882”(http://openassist.googlecode.com/files/C%2B%2B%20Standard%20-%20ANSI%20ISO%20IEC%2014882%202003.pdf)中定义明确。参见“3.6.3 终止”部分第 1 段:<quote>析构函数(12.4)用于静态存储持续时间的初始化对象(在块范围或命名空间范围声明)作为从 main 返回的结果和作为调用的结果被调用退出(18.3)。这些对象按照其构造函数完成或动态初始化完成的相反顺序销毁。</quote> (2认同)