views:

274

answers:

6

I've got a class (A) that accesses (indirectly via a static method) a static variable (an STL container) in another class (B) in its constructor and destructor.

A objects may be global, global constants, static members of another class, stored in other classes (which may themselves have global or static instances) or basically anywhere else a c++ object can be.

If an A object is constructed before the static members in B or destructed after the static members in B, it will cause a crash at some point (usually an access violation).

Is there some way to guarantee that all instances of class A (except those that have leaked, since by definition there "lost" and so wont be destructed any way) are constructed after and destructed before B's static variable?

I've seen some solutions for making a specific variable be constructed/destructed before/after another, however not a general case of all instances of a given type so am not sure how to approach this.

+4  A: 

No. This is known as the static-initialization fiasco. The order that objects get constructed prior to entering main is unspecified. The only guarantee is that it happens.

What you can do is lazy-initialize. This means your objects won't be initialized until you use them. Such as:

struct A { /* some data */ };
struct B { B(void){ /* get A's data */ } };

A& get_A(void)
{
    static A instance;
    return instance;
}

B& get_B(void)
{
    static B instance;
    return instance;
}

You use get_A and get_B to get the global instances. The part where B uses A should use get_A, and your use of B should be with get_B. Note the get_B is optional in your case.

What happens when B is first created? (Either globally or in the function) The constructor will call get_A and that's where A will be created. This let's you control the order things get constructed.

Note I think I reversed your A and B.

GMan
He's asking about destruction, not initialisation.
anon
@Neil: Destruction order is determined by initialization order, though.
GMan
So I can just change my "static Container container" to "static Containerreturn container;}" and it would deallocated after anything that directly or indirectly called getContainer in it's constructor? What if an instance of A was stored into a global shared_ptr at some point later in the program?
Fire Lancer
You're still opening yourself up for trouble, as the previous C++ FAQ entry (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14) mentions regarding static objects vs. static pointers.
jamesdlin
A: 

Static initialization order fiasco.

dirkgently
+1  A: 

In general, no such method. There are workarounds, though. You can get an object with global scope and a slightly-less-than global lifetime by having a global pointer and initializing/destructing it in main/WinMain. Also, you place your global state to be destructed last in a ref-counted heap object.

Also, consider redesign :)

Seva Alekseyev
+1  A: 

The book "Modern C++ Design" covers this issue nicely.

Google Books contains scans of much of it - see section 6.5 (page 135) - link.

stusmith
+1  A: 

You can handle this cleanly, by putting pointers to the objects in global space, then newing them in the desired order in your main, and destroying them in the desired order at the end of the main.

EvilTeach
A: 

As others pointed, there is no standard and portable way to solve this problem, due to the Static initialization order fiasco issue.

However, you should be able to solve your problem by applying a bit of design, so you gain a degree of control when (and how) objects of A and B are constructed. Take a look on design patterns like creational pattern Singleton it is considered in many (if not most) cases as anti-pattern, despite it is worth to learn about it. Also look at to Monostate pattern which may be used as a bit better Singleton. These patterns can help to control object creation and lifetime, so things are properly initialized before use.

Generally, it's a good idea to avoid globals - sticking to deglobalisation is a good idea.

mloskot