How to do static de-initialization if the destructor has side effects and the object is accessed from another static object's destructor?

StackOverflow https://stackoverflow.com/questions/3143180

Question

There is a simple and well-known pattern to avoid the static initialization fiasco, described in section 10.13 of the C++ FAQ Lite.

In this standard pattern, there is a trade-off made in that either the constructed object gets never destructed (which is not a problem if the destructor does not have important side effects) or the static object cannot safely be accessed from another static object's destructor (see section 10.14 of the C++ FAQ Lite).

So my question is: How do you avoid the static de-initialization fiasco if a static object's destructor has important side effects that must eventually occur and the static object must be accessed by another static object's destructor?


(Note: the FAQ-lite mentions this question is answered in FAQ 16.17 of C++ FAQs: Frequently Asked Questions by M. Cline and and G. Lomow. I do not have access to this book, which is why I ask this question instead.)

Was it helpful?

Solution

function static objects like global objects are guaranteed to be destroyed (assuming they are created).

The order of destruction is the inverse of creation.
Thus if an object depends on another object during destruction you must guarantee that it is still available. This is relatively simple as you can force the order of destruction by making sure the order of creation is done correctly.

The following link is about singeltons but describes a similar situation and its solution:
Finding C++ static initialization order problems

Extrapolating to the general case of lazy initialized globals as described in the FAQ lite we can solve the problem like this:

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

OTHER TIPS

As long as the other object's static destructor runs first, you're ok. You can assure this by having the other object get constructed before "object A". As long as both objects are declared in the same compilation unit, they will be initialized in the order they appear in the source, and destructed in the opposite order.

If you need this to happen across compilation units, you're out of luck. Better is to create them dynamically at runtime and destroy them at the end of main, rather than making them static.

It is a bit of a hack but I would add some static bools to keep track of the order of de initialization Then the object that ends up last does the clean up even if it isn't the owner.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top