Constructors for global variables (objects) are not being called
I have a VC++ project B that is linked into a static library "B.lib". This library is linked into project A which creates A.exe. The constructors for the global varaiables in B do not get called.
1. If I have golbal variables in A then there is no problem - the constructors for those get called.
2. I f the solution (Project A and B) get linked on my coleagues computer then there is no problem.
3. The whole soltion is shared between us via rational clearcase so we have the same sources and the same project files.
- so it must be one of the flags of visual studio - but which???
Thanks,
D.
Re: Constructors for global variables (objects) are not being called
Originally Posted by dannyg
I have a VC++ project B that is linked into a static library "B.lib". This library is linked into project A which creates A.exe. The constructors for the global varaiables in B do not get called.
You need to provide a little more information.
Are your global variables reliant on other global variables to be constructed? In other words, does global A require global B to be fully constructed? If so, then there is no standard order of construction of these objects.
If you mean that after main() is called, your global variables are not constructed, that's hard to believe, since after main() is called, globals should have been constructed. This is especially the case if the whole thing is a single executable (no external DLL's, EXE's or other modules have any role in the construction of the global variables).
- so it must be one of the flags of visual studio - but which???
If the problem is what I stated earlier, the easiest thing to do is redesign the program so it doesn't use globals and doesn't rely on one global constructing another global. Otherwise, you will have to produce a small example that shows a complete executable program that shows that the globals are not constructed after the main() entry point has been entered.
Re: Constructors for global variables (objects) are not being called
Hi, dannyg:
I suggest you to make a small B and A and try to use the smaller
programs to reproduce the problem.
If you can reproduce the problem and cannot figure out the solution,
you can attached the smaller programs on this froum so that we can
find out the problem more easily.
Re: Constructors for global variables (objects) are not being called
I tried reconstructing in a small example - but there is no problem there. The project where this happens I cant post here. Again it has to be some flag or bug - if anyone is aware of.
Re: Constructors for global variables (objects) are not being called
I've come across this before.
Static objects in libraries don't get constructed even when the c++ spec says they should be.
Add a dummy method to the offending classes - i.e. a method which does nothing - and call it in the OnInitialise of your application class. This will ensure that they are constructed.
Darwen.
www.pinvoker.com - PInvoker - the .NET PInvoke Interface Exporter for C++ Dlls.
Re: Constructors for global variables (objects) are not being called
Originally Posted by dannyg
I tried reconstructing in a small example - but there is no problem there. The project where this happens I cant post here. Again it has to be some flag or bug - if anyone is aware of.
Again, if the issue is that you are initializing a global that relies on another global being initialized, and both globals are defined in two separate modules, then there is no bug. If this is the case, you are relying on unspecified behaviour.
Global objects that rely on the construction of other global objects is only guaranteed if all the globals are in one module (then the order of initialization is done in the order in which they are declared). If the globals are in different modules, there is no specified order of initialization.
Re: Constructors for global variables (objects) are not being called
Darwen - Thanks - You have isolated the problem.
However your solution is not helping me. The point is that the constructutor of those global object registers to the application that there is another class derived of some common abstract class in the application now. By adding a function to the main code I am defeating the purpose.
The point is not to have to change "main" each time I add a new class to register - thats what the global constructors are for.
I am attaching a small project where I reconstructed the problem - now that I know what it is
The situation is really ugly:
1. I add the dummy function and it solves the problem.
2. I remove the dummy function and there is still no problem.
3. I rebuild the solution and the problem comes back!!!!
Re: Constructors for global variables (objects) are not being called
Originally Posted by dannyg
Darwen - Thanks - You have isolated the problem.
However your solution is not helping me. The point is that the constructutor of those global object registers to the application that there is another class derived of some common abstract class in the application now. By adding a function to the main code I am defeating the purpose.
And I guess everything that I stated was not considered.
You are attempting to come up with a solution to something that isn't specified by C++, and that is the order of static initialization. This is a well-known issue that has been discussed many times over. I can point you to the C++ specification that explicitly states this, if I'm not convincing.
Unless there is a documented way in the compiler settings to initialize static members in a certain order, then there is no order specified order and it's time to rethink your design.
Re: Constructors for global variables (objects) are not being called
Paul,
I have been programming in C++ for almost 20 years on Unix. I just moved to VC++. There is nothing new in what I am doing. The first object that tries to register itself also creates the registery. There is no dependency or assumption on the order of static initialization.
I m interested to know if anyone has heard of this problem or if there is a flag to overcome it.
Re: Constructors for global variables (objects) are not being called
Originally Posted by dannyg
Paul,
I have been programming in C++ for almost 20 years on Unix. I just moved to VC++. There is nothing new in what I am doing.
Then you've relied on unspecified behaviour. I don't know what else to tell you except you have been lucky it has worked -- up until now. BTW, the relevant section in the ANSI specification is 3.6.2 (Initialization of non-local objects).
That section even states that an implementation may "dynamically" initialize the global variable on first use in main(), and all your main() function calls is "testit()".
Re: Constructors for global variables (objects) are not being called
Paul,
1. In the article - the guy there says there is a way to overcome it (#3). I would say thats what I do. I dont think we need to dwell on initialization order anymore.
2. The example I sent demonstrates the problem I have. Try the following. Make sure to use not only the code files but also the project files. a) Build it and see if XX is printed. b) Then uncomment testit in main and see if XX in printed. c) Then comment testit and see if it is printed. Then rebuild and again see if XX is printed.
I am using visual studio 2003.
What I saw:
a) XX not printed.
b) XX printed.
c) XX printed.
d) XX not printed.
Re: Constructors for global variables (objects) are not being called
Originally Posted by dannyg
Paul,
1. In the article - the guy there says there is a way to overcome it (#3). I would say thats what I do. I dont think we need to dwell on initialization order anymore.
Then why are you having the problem? It must be for some reason. You think that your program is well-defined -- it isn't.
What I'm saying is that what you are doing is unspecified by the C++ standard. It isn't a bug in Visual C++. I pointed you to the section in the standard (3.6.2 item 3 to be exact). It no longer is an issue with order of initialization, but when those global objects actually are initialized by the implementation.
You are expecting those global objects declared in different translation units to be initialized, just because main() is called. This is not required by the standard. From 3.6.2, item 3:
It is implementation defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized.
This is then followed by an example showing global objects, and then what the program is and is not guaranteed to happen successfully. Your testit() function is defined in the same translation unit as XX. Therefore it is guaranteed to be instantiated when you call testit(), otherwise it isn't guaranteed.
Maybe this entire thread should be moved to the non-Visual C++ forum. Then others who concentrate more on the language elements, as opposed to the Visual C++ forum, will have input on this issue. Posters such as SuperKoko, Graham, or exterminator (and others) can chime in.
2. The example I sent demonstrates the problem I have. Try the following. Make sure to use not only the code files but also the project files. a) Build it and see if XX is printed. b) Then uncomment testit in main and see if XX in printed. c) Then comment testit and see if it is printed. Then rebuild and again see if XX is printed.
I am using visual studio 2003.
What I saw:
a) XX not printed.
b) XX printed.
c) XX printed.
d) XX not printed.
And this doesn't suggest unspecified behaviour, just like I've been (and the ANSI standard) have been stating? I took your project, and tried it both in Visual Studio 2005 and Visual Studio 2003 -- differing behaviour. The behaviour of VC 2003 matches exactly what is described in section 3.2.6 (3). Only when the testit() function was called was XX constructed.
Re: Constructors for global variables (objects) are not being called
Hi,
Just thought I would post the right answer here:
My mistake was that I tried to compile B as a library. The library linker is "lazy" and does not add module B into the compiled exe because its not referenced directly or indirectly from main. Its not an issue of global constructors at all. If I add module B directly as an object then it works.
Why I would want to add a module that has no reference is a good question: thats where the global constructors come in.
there is a linker flag in VC++ /OPT:NOREF that forces linking but it does not work and there is an open bug on this:
It becomes a methodology question now. On Unix - working with Makfiles, we did not create libraries when we workred as a team. In VC this seems to be the method of choice - but I am new to this so there may be another way to organize a project. The reason we dont want to share project files is similar to the reason you dont want to share makefiles on Unix. You want to own the build process of you component. I would be interested to know if there is a setting in VC++ that lets me keep my code as a bunch of objects rather than a library.
Re: Constructors for global variables (objects) are not being called
The caveat is that the object must produce a side-effect in the constructor or destructor so that it isn't optimized away.
Reading further into the ANSI spec, the link you have states this:
3.7.1
If an object of static storage duration has initialization or a destructor with side effects, it shall not be eliminated even if it appears to be unused, except that a class object or its copy may be eliminated as specified in 12.8.
Section 12.8 is where it is discussed that a compiler can optimize away copy construction or assignment if it sees fit.
Now, the definition of a side-effect is in 1.9
Accessing an object designated by a volatile lvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the
state of the execution environment. Evaluation of an expression might produce side effects.
So if your class constructor or destructor does not do any of these things, the constructor may not be called implicitly for the global object. Then that is where 3.6.2 comes into play, where the constructor of the global will be guaranteed to be called if you call a function that is in the same translation unit as the global object.
So considering this, your constructor calls cout(), which is a library I/O function. Therefore the executable should not have removed the global constructor of XX.
Here is where I may disagree with the bug report (note that no one has addressed it, as far as I see): The example calls "DebugBreak". I don't know if this calls a library I/O function or not. If it doesn't, then I don't know if this reported bug is justified.
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.