C++中POD类型的默认值初始化和值初始化

24

我知道一些POD变量默认情况下会被初始化为有意义的值,但其他变量则不会。(POD类型包括intfloat、指针、联合体、POD类型的数组、POD类型的结构体等)

作用域和存储类别如何影响POD类型的初始化?

具体来说,以下哪些变量将隐式地初始化为已知值(例如整数类型的0)(即值初始化),哪些变量将以不确定的值进行定义(即默认初始化):

  • 自动存储的局部变量
  • 静态局部变量
  • 静态全局变量
  • 外部变量
  • 使用new分配的变量
  • 类的POD成员(在构造函数中没有显式初始化的情况下)

我知道关于其中一些情况已经有相关问题,但没有一个是全面的(它们只涉及特定的情况)。


2
“modifier” 是什么意思?不要混淆 static 存储类别说明符和静态存储期,前者对初始化没有影响,后者有。 - Jonathan Wakely
1
是的,我指的是存储类。已修复。 - Daniel Hanrahan
@JonathanWakely,我认为你当时混淆了_linkage_和_storage duration_ (嘿嘿,正好是10年前的今天,十周年快乐!:)。从cppreference的**Storage class specifiers**页面可以看出(请注意URL本身已经说了:“storage_duration”...):“static - static或thread storage duration和internal linkage”。我的意思是,毫无疑问,整个C++标准都是一个越来越令人困惑的定义黑洞,特别是关于初始化方面... :) - Sz.
2个回答

27
具有自动存储期的局部变量不会自动初始化。由于使用未初始化的变量会产生undefined behavior,因此在即使多余的情况下也要显式初始化您的变量是一个好习惯。
关于被零初始化的POD类型,C++03标准3.6.2 Initialization of non-local objects说明:
对象具有静态存储期(3.7.1)的对象在进行任何其他初始化之前必须进行零初始化(8.5)。零初始化和用常量表达式初始化统称为静态初始化;所有其他初始化都是动态初始化。使用常量表达式初始化的POD类型(3.9)的具有静态存储期的对象必须在进行任何动态初始化之前进行初始化。
因此,标准保证了具有静态存储期的POD类型(无论其作用域如何)将被零初始化。
此情况在12.6.2 Initializing bases and members中进行了描述,该部分说明(选定部分):
如果一个非静态数据成员或基类没有被 mem-initializer-id 命名(包括构造函数没有 ctor-initializer 的情况),则: - 如果该实体是非静态数据成员,并且实体类是非 POD 类,则该实体将进行默认初始化(8.5)... - 否则,该实体未初始化... 在类 X 的构造函数调用完成后,如果 X 的成员既没有在构造函数的 mem-initializers 中指定,也没有进行默认初始化、值初始化或在构造函数体执行期间给出值,则该成员的值是不确定的。 示例:
class C
{
public:
    C(int x, int z) : x(x), z(z) { }
    int x, y, z;
};

int main(void)
{
    C* c = new C(1,3);
    std::cout << c->y; // value of y is undetermined !!!
}

1
使用未初始化的变量会产生未定义的行为可能有点太严格了。读取它们的值才是UB。如果在读取变量之前分配一个值(可能比对象创建时间晚得多),那么就没问题了。 - Spencer

13
如果我们只谈论POD,那么只有局部和全局静态变量以及外部变量需要被定义。使用new分配的POD也会有时候被初始化 - 如果你显式地进行初始化。
int* x = new int();

将创建一个初始化为0int,并将x指向它,而

int* x = new int;

这段代码将使x指向一个未初始化的int

有时候 - POD类成员 - 可以被显式地初始化(而不需要在构造函数中):

struct X
{
   int x;
};

X x;        //x.x is not initialized
X y = X();  //y.x is 0

我对最后一种情况很好奇:如果有一个构造函数,但它没有初始化 x,那么 X() 会将 x 初始化为0吗?也就是说,如果你有一个构造函数,是否需要初始化所有 POD 类型? - Daniel Hanrahan
@QuasarDonkey:请检查我的答案,我在底部添加了一个示例。 - LihO

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接