在和同事讨论后,我产生了一些疑问......
正如标题所问,什么时候可以假设内置类型将被初始化为 0 而不是未知值?
c++ 标准之间的规则是否有所不同?
在和同事讨论后,我产生了一些疑问......
正如标题所问,什么时候可以假设内置类型将被初始化为 0 而不是未知值?
c++ 标准之间的规则是否有所不同?
完整的规则在 [dcl.init] (C++11) 中。总结一下:当声明中没有提供初始化器时,实体被称为默认初始化。对于类类型,这意味着调用默认构造函数。对于非类类型,这意味着不执行初始化。
但是,[dcl.init] §9 规定:“在程序启动时,在任何其他初始化发生之前,每个静态存储持续时间的对象都被初始化为零。”
这意味着非类类型的静态持续时间变量(例如命名空间范围变量)是零初始化的。非类类型的其他对象(例如局部变量)未初始化。
根据C++98和C++03标准:
3.6.2 非本地对象的初始化,§1:
具有静态存储持续时间(3.7.1)的对象应在任何其他初始化发生之前进行零初始化(8.5)。
3.7.1 静态存储持续时间,§1:
所有既不具有动态存储持续时间也不是本地对象的对象具有静态存储持续时间。
3.7.1 静态存储持续时间,§3:
该关键字
static
可用于声明具有静态存储持续时间的局部变量。
还有8.5 Initializers, §6:
每个静态存储持续时间的对象都应在程序启动时进行零初始化,然后再进行任何其他初始化。
这在两个标准中是相同的。唯一的区别在于C++98 的 8.5 §6 的制定:
任何具有静态存储持续时间的对象所占用的内存都应在程序启动时进行零初始化,然后再进行任何其他初始化。
这是示例,其中x
和y
具有静态存储持续时间,因此标准保证它们在程序启动时都将被零初始化。请注意,还有 POD 对象a
并b
以相同的方式声明,因此具有静态存储持续时间,这意味着它们的成员 (i
和d
) 也将被零初始化:
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
而不是回答您发布的确切问题,之前已回答:只有具有静态存储的 POD 对象将自动初始化为 0,我将尝试提供一些代码来让编译器为您初始化成员:
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 在某些情况下存在一些问题(IIRC T t = T();
,T* p = new T()'
当类型T
不是 POD,但没有用户提供的默认构造函数时,编译器将无法初始化 POD 子对象:
struct T {
std::string s;
int i;
};
void f() {
T t = T(); // t.i == 0 according to the standard
}
我不会假设任何隐式类型都将初始化为 0。当您在调试器内部运行并使用调试堆/堆栈时,您可能会发现这种情况。当您在调试器之外或通过 _NO_DEBUG_HEAP=1 环境变量禁用调试堆时,您会发现大多数情况下内存未初始化。
根据经验,初始化变量,因为以这种方式编程更安全。
编辑:正如 Luchian Grigore 所指出的,全局/命名空间范围变量是一个例外。由于这种初始化,它们通常也不适用于未初始化的变量检查。