POD全局对象初始化

时间:2010-06-02 18:10:23

标签: c++ initialization global-variables pod

我今天被一个小虫咬了。

C ++律师的问题

让我们考虑以下来源:

struct MyPod
{
   short              m_short ;
   const char * const m_string ;
} ;

MyPod myArrayOfPod[] = { { 1, "Hello" } } ;

int main(int argc, char * argv[])
{
   return 0 ;
}

请注意,所有值在编译时都是已知的,并且MyPod是POD。

那么,myArrayOfPod应该在编译时初始化,还是编译器会生成MyPod的默认构造函数?

详细信息,包括自包含的来源

可以将以下复制/粘贴错误的源复制/粘贴到main.cpp文件中:

#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是POD,我相信没有构造函数。只在编译时初始化。

因此,全局对象SomeGlobalObject在构造时使用全局POD数组没有问题。

但是,在Visual C ++ 2008中,在调试模式下,执行myArrayOfPod时未正确初始化(其所有值都为零),即使myArrayOfVoid已正确初始化。

所以我的问题是: C ++编译器是不是应该在编译时初始化全局POD(包括POD结构)?

Displaimer

请注意,我知道全局变量是邪恶的,我知道无法确定在不同编译单元中声明的全局变量的创建顺序,但这是无题的:问题是关于全局变量POD初始化。

修改

我在Ubuntu上复制/粘贴了这段代码,就g ++ 4.4.3而言,这两个数组在调试和发布模式下都已正确初始化。

此行为已报告给Microsoft,等待确认: https://connect.microsoft.com/VisualStudio/feedback/details/564844/pod-struct-global-object-initialization-uses-constructor

编辑2

Visual C ++ QA回答了错误提交,引用了标准(至少n3092)。就它们而言,Visual C ++上看到的行为确实遵循标准。

尽管我的“感觉”这仍然是一个错误,但我必须承认他们比我更了解标准的事实(如果只是因为我使用语言,当他们编写语言的编译器,从而接受他们的答案。

所以,我会做我的作业,也就是说,我会从头到尾阅读n3092(一千页律师般的陈述......这是我的运气......):这个文档使用了很多明确定义的单词,如果我不知道每个单词的确切含义,那么我就无法引用一些n3092段来支持我的观点......

感谢MSNAndreyT的回答。

4 个答案:

答案 0 :(得分:3)

根据C ++标准,3.6.2.2:非本地对象的初始化:

  

一起,零初始化和   调用常量初始化   静态初始化;所有其他   初始化是动态的   初始化。静态初始化   应在任何动态之前执行   初始化发生。

由于myArrayOfPod至少乍一看是用常量表达式初始化的,所以它应该在oSomeGlobalObject之前初始化。它不在调试中的事实可能是一个错误。您可以通过connect.microsoft.com提交错误。

答案 1 :(得分:1)

C ++语言保证使用常量表达式初始化静态存储持续时间的POD对象静态,即“在编译时”。更讽刺的是,无论如何实现静态初始化(在编译时,在运行时),都必须在之前进行任何动态初始化。例如,构造函数调用是动态初始化。

在您的情况下myArrayOfPod是POD,整数文字是整数常量表达式,字符串文字是地址常量表达式。我会说你的myArrayOfPod满足所有要求,因此必须静态初始化。如果您在实验中从myArrayOfPod的构造函数中观察到未初始化的oSomeGlobalObject,那么它必定是编译器中的错误。

答案 2 :(得分:0)

对我来说,似乎是全局变量初始化的顺序,而不是它们是否。必须是Debug模式以与发布模式不同的顺序调用全局初始化代码。

Globals引用全局...可以有一定程度的邪恶? ; - )

编辑: 据推测,如果你将两个cout放在main中,你会看到所有的全局变量都是在它到达那里时被初始化的。

答案 3 :(得分:0)

C ++编译器不应该在编译时初始化全局POD(包括POD结构)吗?

没有。他们怎么样?它们是运行时构造。即使编译器在程序的描述中构建了所有内容(堆栈上的常量值),它仍然必须在运行时初始化。

IRC,在同一个翻译单元中,全局变量的初始化顺序保证按声明的顺序排列。考虑将某个全局对象放置在文件中的位置。

如果我错了,那么订单是不确定的。此外,当我们讨论跨翻译单元的全局变量时,顺序是未定义的。其中我肯定。