什么时候C ++隐式类型初始化为0?

时间:2013-02-08 13:56:54

标签: c++ initialization built-in-types

在与同事讨论之后,我产生了一些疑问......

如标题所示,何时可以假设内置类型将初始化为0而不是未知值?

规则是否因c ++标准而异?

4 个答案:

答案 0 :(得分:6)

完整规则在[dcl.init](C ++ 11)中。总结一下:当声明中没有提供初始化时,实体就是所谓的 default-initialised。对于类类型,这意味着调用默认构造函数。对于非类类型,这意味着不执行初始化。

但是,[dcl.init]§9声明:“在进行任何其他初始化之前,静态存储持续时间的每个对象在程序启动时都是零初始化的。”

这意味着非类型的静态持续时间变量(例如命名空间范围变量)是零初始化的。非类类型的其他对象(例如局部变量)初始化。

答案 1 :(得分:3)

理论值:

根据 C ++ 98 C ++ 03 标准:

3.6.2非本地对象的初始化,§1

  

具有静态存储持续时间(3.7.1)的对象应在进行任何其他初始化之前进行零初始化(8.5)。

3.7.1静态存储持续时间,§1

  

所有既没有动态存储持续时间也没有本地的对象都有静态存储持续时间。

3.7.1静态存储持续时间,§3

  

关键字static可用于声明具有静态存储持续时间的局部变量。

还有 8.5初始值设定项,§6

  

在进行任何其他初始化之前,静态存储持续时间的每个对象都应在程序启动时进行零初始化。

这两个标准都是一样的。唯一的区别在于 C ++ 98的8.5§6

的制定
  

静态存储持续时间的任何对象占用的内存应为零初始化   在程序启动之前进行任何其他初始化。


实施例

以下是xy并且具有静态存储持续时间的示例,因此标准保证在程序启动时它们都将被初始化为零。请注意,还有以相同方式声明的POD对象ab,因此具有静态存储持续时间,这意味着他们的成员(id)将是零初始化:

struct POD {
    int i;
    double d;
};

int x;
POD a;

int foo() {
    static int y;
    return y;
}

int main() {
    static POD b;
    std::cout << "x   = " << x      << std::endl;
    std::cout << "y   = " << foo()  << std::endl;
    std::cout << "a.i = " << a.i    << std::endl;
    std::cout << "b.d = " << b.d    << std::endl;
}

当然,这个例子的输出是:

x   = 0
y   = 0
a.i = 0
b.d = 0

答案 2 :(得分:3)

不是回答你发布的确切问题,而是之前已经回答过:只有静态存储的POD对象会自动初始化为,我会尝试提供一些代码来获取编译器为您初始化成员:

struct POD {
   int    a;
   double b; //...
};
// namespace level:
POD p;
void f() {
   POD n1;                  // uninitialized
   POD p1 = {};
   POD p2 = POD();
   POD* n2 = new POD;       // uninitialized
   POD* pp1 = new POD();
   delete n2; delete pp1;
}

在上面的示例中,只有那些标有“未初始化”的标签才会被初始化。请注意,这与标准要求有关,您的里程数会因不同的编译器而异。特别是VS在某些情况下T t = T();T* p = new T()'存在一些问题(IIRC类型T不是POD,但没有用户提供的默认构造函数,编译器将无法初始化POD子对象:

struct T {
   std::string s;
   int         i;
};
void f() {
   T t = T();    // t.i == 0 according to the standard
}

答案 3 :(得分:-1)

我不会假设任何隐式类型将被初始化为0.当您在调试器内部运行并使用调试堆/堆栈时,您可能会发现这种情况。当您在调试器之外或通过_NO_DEBUG_HEAP = 1环境变量禁用调试堆时,否则您会发现在大多数情况下内存未初始化。

根据经验,初始化变量,因为以这种方式编程更安全。

编辑:正如Luchian Grigore所指出的,全局/命名空间范围变量是一个例外。由于初始化,它们通常也不能与未初始化的变量检查一起使用。