使用具有自动存储持续时间的内置类型的未初始化对象是未定义的行为。当然,我强烈建议在类类型中初始化内置类型的成员变量。尽管如此,我假设如果类类型的相应对象具有静态存储持续时间(即全局对象),则没有初始化器的内置类型的成员总是初始化为零。我的假设是,具有静态存储持续时间的类类型对象的完整内存被清零。
例:
#include <iostream>
using namespace std;
class Foo {
public:
int bar;
};
Foo a;
int main() {
Foo b;
cout << "a.bar " << a.bar << "\n";
cout << "b.bar " << b.bar << "\n";
return 0;
}
编译:
$ g++ -o init init.cpp -Wall -pedantic # gcc 7.2.1
init.cpp: In function ‘int main()’:
init.cpp:14:31: warning: ‘b.Foo::bar’ may be used uninitialized in this function [-Wmaybe-uninitialized]
cout << "b.bar " << b.bar << "\n";
^~~~
GCC仅抱怨具有自动存储持续时间b.bar而不是a.bar的类类型对象的成员。所以我是对的?
请随时修改此问题的标题。
谢谢
正如评论中所述,它是零初始化,[basic.start.init]/3:
具有静态存储持续时间([basic.stc.static])或线程存储持续时间([basic.stc.thread])的变量在进行任何其他初始化之前应进行零初始化([dcl.init])。[... ]
零初始化一个对象,零初始化所有非静态数据成员和填充位,[dlc.init]/6.2:
零初始化T类型的对象或引用意味着:[...]
- 如果T是一个(可能是cv限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化的,并且填充初始化为零位; [...]
所以,正如你所说的那样,整个对象存储器被清零(属于其值表示的位和它的填充位)。
不初始化具有自动存储持续时间的内置类型的对象是未定义的行为。
不,那不对。见[dcl.init]/12:
如果没有为对象指定初始化程序,则默认初始化该对象。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,并且如果没有对该对象执行初始化,则该对象保留不确定的值,直到该值被替换([expr.ass])。 [注意:具有静态或线程存储持续时间的对象是零初始化的,请参见[basic.start.static]。 - 结束注释]如果评估产生不确定的值,则行为是不确定的,除非在以下情况中:
Foo b;
是定义的行为,cout << "b.bar " << b.bar << "\n";
(在b.bar
之前有一个设定值)是未定义的行为。
GCC仅抱怨具有自动存储持续时间b.bar而不是a.bar的类类型对象的成员。
GCC的与未初始化变量相关的警告系列是为了方便而提供的,通常包含误报。在一般情况下,不可能对每个场景都有准确的警告(这与解决暂停问题一样困难)。它只是让你知道你正在尝试使用一个你没有明确初始化的值,即具有不确定的值,这可能不是你想要的。