C++隐式类型何时初始化为0

When are C++ implicit types initialized to 0?

本文关键字:初始化 何时 类型 C++      更新时间:2023-10-16

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

正如标题所问,什么时候可以假设内置类型将初始化为0而不是未知值?

c++标准之间的规则是否不同?

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

然而,[dcl.init]§9指出:"在任何其他初始化发生之前,静态存储持续时间的每个对象在程序启动时都是零初始化的。"

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

我将尝试提供一些代码,让编译器为您初始化成员:

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
}

理论:

根据C++98C++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

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

根据经验,初始化变量,因为这样编程更安全。

编辑:正如Luchian Grigore所指出的,全局/命名空间范围变量是一个例外。由于这种初始化,它们通常也无法处理未初始化的变量检查。