Advertisement

Order of creation/destruction of auto objects?

Started by August 29, 2001 10:21 AM
3 comments, last by Sean99 23 years, 5 months ago
I''m not sure, but I think I remember reading somewhere that you are not guaranteed that the creation and destruction of automatically (non-dynamically) created objects will occur in a specific order. For example, if you declare Class1 object1; Class2 object2; globally, you are not guaranteed that object1 is created before object2. Is this true? I am asking because I was making this assumption without even thinking about it in my program, and in my case, object1 is a log object which needs to be created first and destroyed last because all the constructors and deconstructors of other classes write to the log. I have recompiled and run my program almost daily for several months and so far every other constructor and destructor has been able to write to the log without a problem. So I need to know if I have just been lucking out (and therefore need to change my program to dynamically allocate all of my objects so I can control the order of creation/destruction), or if auto-allocated objects are guaranteed to be created in decared order and destroyed in reverse order. I am using DJGPP for DOS. Thanks in advance, -Sean
"we need common-sense judges who understand that our rights were derived from God. And those are the kind of judges I intend to put on the bench." - GW Bush"no religious Test shall ever be required as a Qualification to any Office or public Trust under the United States." - Article VI of the US Constitution.
I think construction order is as specified by the code.

Because stuff like

MyClass a;

a.Something();

a.Else();

MyOtherClass b;

Is supposed to guarantee that object ''b'' does not get constructed before Else() returns.

However destruction of stack-local objects is probably a bit more up in the air.

To Guarantee the behavior you want, just put in a scope. ( hopefully the compiler won''t optimize it away

eg.

Class1 object1;
if(true)
{
Class2 object2;
}

This will guarantee that object1 is constructed first and lasts longer than object2.

If the optimizer has a fit and removes the if(true) there might be another way to make an embedded scope for the second object.
Advertisement
That is correct: global-scope automatic objects are created in an arbitrary order, at least across modules. I''m not sure about within the same module. The order is not something you should rely on.

If your static object is used to log things like ctors, I would suggest creating a "LoggedObject" class:
- The ctor keeps a reference count (static), and on the first added reference it initializes your logging handles.
- The dtors subtract from the reference count and release the logging handles.
- Derive each class you''d like to have access to the logger from LoggedObject. (If you only want the logging functions available internally, inherit privately; otherwise, inherit publicly and all clients of those classes can use the logger functions.)

This guarantees that the logger will be constructed first, even if all of your logged classes are global-scope automatic objects, and it will only shut itself down after all logged objects have destroyed themselves.
If you need to strictly control the order, I''d recommend encapsulating these static objects inside one other object: that gives you the ability to destroy them in a predictable order. The only problem is how you access them. They could be public members if you liked: after all, they were global anyway.
In a translation unit, the order of global objects is initialized in first come and destructed in reverse order.

So,

object1 obj1;
object2 obj2;

in 1 cpp file, object 1 is guranteed to be created b4 obj2. If you place obj2 in another cpp file, then you are screwed.

A common singleton implementation will not work because you cannot control the destruction order.

The solution is to use a nifty counter technique (search the comp.lang.c++.moderated or C++ Faqs)

The rundown is

Every cpp file creates a global static counter_object.

This counter_object initializes the logging class(must be pointer) if it''s static counter is zero and deallocate the logging class when it is zero.

It works because you include the an instance of the static counter in every cpp file, and as above, global initialization order in a cpp file is well defined.

The problem is nifty counter is every cpp file must be loaded at startup/shutdown time so startup/shutdown times will increase.

This topic is closed to new replies.

Advertisement