I've got bitten today by a bug.
Question for the C++ lawyers
Let's consider the following source :
struct MyPod
{
short m_short ;
const char * const m_string ;
} ;
MyPod myArrayOfPod[]开发者_高级运维 = { { 1, "Hello" } } ;
int main(int argc, char * argv[])
{
return 0 ;
}
Note that all values are known at compile time, and that MyPod is a POD.
So, should myArrayOfPod be initialized at compile time, or will some default constructor of MyPod be generated by the compiler ?
Details including a self-contained source
The following source which reproduces the error, can be copy/pasted into a main.cpp file:
#include <iostream>
// The point of SomeGlobalObject is for its
// constructor to be launched before the main
// ...
struct SomeGlobalObject
{
SomeGlobalObject() ;
} ;
// ...
// Which explains the global object
SomeGlobalObject oSomeGlobalObject ;
// A POD... I was hoping it would be constructed at
// compile time when using an argument list
struct MyPod
{
short m_short ;
const char * const m_string ;
} ;
// declaration/Initialization of a MyPod array
MyPod myArrayOfPod[] =
{ { 1, "Hello" }, { 2, "World" }, { 3, " !" } } ;
// declaration/Initialization of an array of array of void *
void * myArrayOfVoid[][2] =
{ { (void *)1, "Hello" }, { (void *)2, "World" }, { (void *)3, " !" } } ;
// constructor of the global object... Launched BEFORE main
SomeGlobalObject::SomeGlobalObject()
{
// The two values should be "1"
std::cout << "myArrayOfPod[0].m_short : " << myArrayOfPod[0].m_short << std::endl ;
std::cout << "myArrayOfVoid[0][0] : " << myArrayOfVoid[0][0] << std::endl ;
}
// main... What else ?
int main(int argc, char* argv[])
{
return 0 ;
}
MyPod being a POD, I believed there would be no constructors. Only initialization at compile time.
Thus, the global object SomeGlobalObject
would have no problem to use the global array of PODs upon its construction.
But, in Visual C++ 2008, on debug mode, upon execution myArrayOfPod
is not properly initialized (all its values are zero-ed), even if myArrayOfVoid
is correctly initialized.
So my questions is: Are C++ compilers not supposed to initialize global PODs (including POD structures) at compilation time ?
Displaimer
Note that I know global variable are evil, and I know that one can't be sure of the order of creation of global variables declared in different compilation units, but this is out-of-topic: The question is about global POD initialization.
Edit
I copy/pasted this code on my Ubuntu, and as far as g++ 4.4.3 is concerned, the two arrays are correctly initialized in both debug and release mode.
The behaviour was reported to Microsoft, and awaiting confirmation: https://connect.microsoft.com/VisualStudio/feedback/details/564844/pod-struct-global-object-initialization-uses-constructor
Edit 2
Visual C++ QA answered the bug submission, quoting the standard (at least, n3092). As far as they are concerned, the behaviour seen on Visual C++ does follow the standard.
And despite my "feeling" this is still a bug, I must acknowledge the fact they know the standard infinitely more than I do (if only because I use the language, when they write a compiler for the language), and thus accept their answer.
So, I'll do my homework, that is, I'll read n3092 from start to end (A thousand pages of lawyer-like statements... This is my luck...): This document uses a lot of well-defined words, and if I don't know the exact meaning of each word, then there's no way I can quote some n3092 paragraph to support my viewpoint...
Thanks to MSN and AndreyT for their answers.
According to the C++ standard, 3.6.2.2: Initialization of non-local objects:
Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.
Since myArrayOfPod
is at least at first glance initialized with a constant expression, it should be initialized before oSomeGlobalObject
. The fact that it isn't in debug is probably a bug. You can submit a bug through connect.microsoft.com.
C++ language guarantees that POD objects with static storage duration initialized with constant expressions are initialized statically, i.e. "at compile time". More pedantically, regardless of how static initialization is implemented (at compile time, at run time), it must take place before any dynamic initialization. A constructor call, for example, is dynamic initialization.
In your case myArrayOfPod
is a POD, integer literals are integer constant expressions, and string literals are address constant expressions. I'd say that your myArrayOfPod
satisfies all requirements and therefore must be initialized statically. If you observe uninitialized myArrayOfPod
from the constructor of oSomeGlobalObject
in your experiment, it must be a bug in the compiler.
To me it seems like it is a point of which order the globals are initialized, not whether they are. It must be the Debug mode calls the global initialization code in a different order than release mode.
Globals referencing globals... can there be degrees of evil? ;-)
Edit: Presumably if you put the two cout's in main you'll see all the globals have been initialized by the time it gets there.
Are C++ compilers not supposed to initialize global PODs (including POD structures) at compilation time ?
No. How would they? They are runtime constructs. Even if the compiler built everything into the program's description (constant values on the stack) it still has to be initialized at runtime.
IRC, within the same translation unit the initialization order of globals is guaranteed to be in order of declaration. Consider where the placement of your some global object within the file.
If I'm wrong about that then the order is undefined. Furthermore, when we're talking about globals across translation units the order is undefined. Of that I'm sure.
精彩评论