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

有一个简单且众所周知的模式可以避免静态初始化失败,如section 10.13 of the C++ FAQ Lite中所述。

在此标准模式中,存在一种权衡,要么构造的对象永远不会被析构(如果析构函数没有重要的副作用,这不是问题),要么不能从另一个静态对象的析构函数安全地访问静态对象(参见section 10.14 of the C++ FAQ Lite)。

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


(注:FAQ-lite提到这个问题在M.Cline和G.Lomow的C++FAQ:常见问题解答的FAQ 16.17中得到了回答。我没有访问这本书的权限,这就是为什么我问这个问题。)


解决方案

函数保证销毁全局对象等静态对象(假定它们已创建)。

销毁顺序与创建顺序相反。
因此,如果一个对象在销毁过程中依赖于另一个对象,您必须保证它仍然可用。这相对简单,因为您可以通过确保正确执行创建顺序来强制销毁顺序。

以下链接是关于Singelton的,但描述了类似的情况及其解决方案:
Finding C++ static initialization order problems

根据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;
    }
}

相关文章