我最近遇到了我的一个类的问题,因为我没有在构造函数初始化列表中设置指向NULL的指针,所以当我运行程序时它包含垃圾。
然而,虽然我知道在堆栈上声明但未初始化的内置类型的实例将包含随机值,但我很确定我会在某处读取类别成员未明确放置在构造函数初始化器中list会有他们的默认构造函数,对于内置类型,这也会发生,插入代码就像伪构造函数一样,在大多数平台上,将它们设置为零我也认为我读过' Thinking在C ++'某些情况下,在构造一个对象之前的某些情况下,它的记忆将被清零,但在两种情况下我似乎都是错误的。
请有人向我确认,
a)内置类型成员的初始化与是否定义了用户定义的构造函数有关,
b)内置类型的成员总是需要手动初始化,并且
c)在构造函数被调用之前,是否有任何情况下对象的存储被清零?
此外,在研究这个问题时,我已经看到了“默认初始化”这几个术语'并且'零初始化'使用 - 说:
之间有区别吗?T a;
和
T a();
?我认为第一种形式只是用来防止模糊,当编译器将第二种形式作为函数声明时。
非常感谢你的时间,
stellarpower
答案 0 :(得分:12)
首先让我们来看一些示例和正确的术语。
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.对于指针类型,值初始化将其设置为null。默认初始化对标量类型没有任何作用。因此,如果标量类型的对象仅接收默认初始化,则它具有不确定的值。
a)内置类型成员的初始化是否与定义用户定义的构造函数有关,
类的默认构造函数default-initializes成员。如果没有为其明确提供 mem-initializer ,则还会对成员进行默认初始化。示例C1
和C2
说明了这一点。但是,请注意,当类类型被值初始化,并且类的默认构造函数被隐式定义或显式默认时,类的成员将被清零。这种归零仅在这种情况下发生,并且对于用户提供的默认构造函数不会发生。所以问题的答案是"是的"从这个意义上说。
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:其中类对象是值初始化的,其构造函数不是用户提供的(或删除的)。另一种情况是类对象具有静态或线程本地存储持续时间。在这种情况下,成员也会在一开始就被清零,因此他们没有机会以不确定的价值结束。
答案 1 :(得分:1)
您要查找的术语是默认初始化的。如果未在构造函数体中显式初始化任何实例数据成员,则将对其进行默认初始化。这意味着什么取决于数据成员是否是原始数据类型以及对象实例化发生的位置。对于非原始数据类型的数据成员,将使用默认构造函数(或者如果没有默认构造函数,编译器将会抱怨)。对于原始数据类型的数据成员,这意味着如果实例化发生在堆栈上或堆上,则不会初始化它们。但是,如果它是全局变量或静态变量,则数据成员将设置为0。
顺便说一下,当你写
T a;
然后你定义一个类型为T的变量a。当你写
T a();
然后你声明一个函数a(),它按值返回T.
答案 2 :(得分:1)
默认初始化所有成员变量而不调用构造函数的一种方法是使用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分配所需的内存并将指针强制转换为所需的类型。除非绝对必要,否则你应该避免这种情况!