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

时间:2010-06-29 17:26:26

标签: c++ destructor static-initialization initialization-order

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

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

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


<子> (注意:FAQ-lite提到这个问题在M. Cline和G. Lomow的 C ++ FAQs:常见问题的FAQ 16.17中得到了解答。我无法访问这本书,这是为什么我会问这个问题。)

3 个答案:

答案 0 :(得分:4)

保证破坏全局对象等函数静态对象(假设它们已被创建)。

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

以下链接是关于singeltons,但描述了类似的情况及其解决方案:
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;
    }
}

答案 1 :(得分:0)

只要另一个对象的静态析构函数首先运行,你就可以了。您可以通过在“对象A”之前构造其他对象来确保这一点。只要两个对象都在同一个编译单元中声明,它们就会按照它们在源中出现的顺序进行初始化,并以相反的顺序进行破坏。

如果您需要在编译单元中进行此操作,那么您运气不佳。更好的方法是在运行时动态创建它们并在main结束时销毁它们,而不是将它们静态化。

答案 2 :(得分:0)

这有点像黑客,但我会添加一些静态bool来跟踪de初始化的顺序然后,即使它不是所有者,最后结束的对象也会进行清理。