是否内置类型的成员从未默认初始化

Are members of a built-in type ever default-initialised?

本文关键字:默认 初始化 成员 内置 置类型 是否      更新时间:2023-10-16

我最近在我的一个类中遇到了一个问题,因为我没有在构造函数初始化列表中设置指向NULL的指针,所以当我运行程序时它包含垃圾。

然而,虽然我知道在堆栈上声明但未初始化的内置类型的实例将包含随机值,但我很确定我在某个地方读到,作为未显式放置在构造函数初始化列表中的类成员将调用其默认构造函数,对于内置类型,这也会发生,插入代码像伪构造函数一样,将在大多数平台上,我还以为我在"c++思维"中读到过,在某些情况下,在一个对象被构造之前,它的内存将被归零,但是我似乎在这两种情况下都是错误的。

谁能帮我确认一下,
a)内置类型成员的初始化是否与用户定义的构造函数是否定义有关?
b)内置类型的成员是否总是需要手工初始化
c)在调用构造函数之前,是否存在对象存储为零的情况?

另外,在研究这个问题时,我看到了"默认初始化"answers"零初始化"这两个术语的使用——这两者有区别吗?

T a;

T a();

?我认为第一种形式只是用来防止歧义,而第二种形式可能被编译器作为函数声明。

非常感谢您的宝贵时间,

stararpower

首先让我们看一些例子和正确的术语

T a1;            // default initialization
T a2{};          // value initialization
T();             // also value initialization
new T;           // default initialization
new T();         // value initialization
new T{};         // also value initialization
class C1 {
    C1() {}
    T x;
};               // no initializer for C1::x; default-initialized
class C2 {
    T x;
};               // implicit default constructor default-initializes C2::x
class C3 {
    C3() : x() {}
    T x;
};               // C3::x will be value-initialized.
class C4 {
    C4() : x{} {}
    T x;
};               // C4::x will also be value-initialized.
// DANGER
T a();           // declares a function; not value initialization (quirk of C++)

一般来说,规则是当没有初始化器时为默认初始化,当初始化器为(){}时为值初始化。请注意,静态静态和线程局部变量有一个例外,我将在后面讨论。

对于整型或浮点型,值初始化将其设置为0。对于指针类型,值初始化将其设置为空。默认初始化对标量类型没有任何作用。因此,如果标量类型的对象只接收默认初始化,则它具有不确定的值。

a)内置类型成员的初始化与用户定义的构造函数是否定义有关系吗,

类的默认构造函数默认初始化成员。当没有显式地为成员提供mem初始化器时,成员也被默认初始化。C1C2的例子说明了这一点。但是,请注意,当类类型为值初始化时,并且类的默认构造函数是隐式定义的或显式默认的,则该类的成员将被归零。这种归零只发生在这种情况下,而不会发生在用户提供的默认构造函数中。所以从这个意义上说,你的问题的答案是"是"。

C1 y1;   // y1 is default-initialized; y1.x is indeterminate
C1 y2{}; // y2 is value-initialized;   y2.x is indeterminate
C2 y3;   // y3 is default-initialized; y3.x is indeterminate
C2 y4{}; // y4 is value-initialized;   y4.x is set to 0
C3 y5;   // y5 is default-initialized; y5.x is set to 0
C3 y6{}; // y6 is value-initialized;   y6.x is set to 0

b)内置类型的成员是否总是需要手动初始化,c)在调用构造函数之前是否存在对象存储为零的情况?

我想你的意思是"内置类型的类成员"。我在上面介绍了一种情况,在这种情况下,它们被自动初始化为0:类对象是值初始化的,并且它的构造函数不是用户提供的(或删除的)。另一种情况是类对象具有静态或线程本地存储持续时间。在这种情况下,成员也将在一开始就被归零,因此它们不可能以不确定的值结束。

您正在查找的术语是默认初始化的。如果没有在构造函数体中显式初始化,则将默认初始化任何实例数据成员。这意味着什么取决于数据成员是否是基本数据类型以及对象实例化发生的位置。对于非基本数据类型的数据成员,将使用默认构造函数(或者如果没有默认构造函数,编译器将报错)。对于原始数据类型的数据成员,这意味着如果实例化发生在堆栈或堆上,则不会初始化它们。但是,如果它是全局变量或静态变量,则数据成员将被设置为0。

顺便说一下,当你写 的时候
T a;
那么你定义了一个t类型的变量a,当你写
T a();

则声明一个函数a(),它按值返回T。

默认初始化所有成员变量而不调用构造函数的一种方法是,如果您有POD类型。例如,这是一个POD

class Foo {
    int num1;
    double num2;
    bool b;
    int *pnum;
};

如果你做了

Foo foo = {};

所有内容都将被零初始化(b将为false, pnum为NULL等),而不调用(默认)构造函数。

a) POD类型不能有用户定义的构造函数,在这种情况下是

b)如果您有POD,则不必手动初始化它们

c)如果你有一个POD类型,你可以零初始化而不调用构造函数。

另一种不调用构造函数创建类实例并进行零初始化的方法是使用calloc分配所需的内存,并将指针强制转换为所需的类型。除非绝对必要,否则你应该避免这样做!