今天我开始了解 C++ 中的 3 种初始化类型:
- 零初始化
- 默认初始化
- 值初始化
我用谷歌搜索了它,但没有找到令人满意的结果。我得到的只是一些标准。到目前为止我所理解的是:在值初始化的情况下,数据成员在某些情况下可以获得等于零的值。
请举例说明它们(标准)。另外请不要只提供标准中的文本。
谢谢
今天我开始了解 C++ 中的 3 种初始化类型:
我用谷歌搜索了它,但没有找到令人满意的结果。我得到的只是一些标准。到目前为止我所理解的是:在值初始化的情况下,数据成员在某些情况下可以获得等于零的值。
请举例说明它们(标准)。另外请不要只提供标准中的文本。
谢谢
初始化的类型参考语言语法。这里有两个例子:
T * p1 = new T;
T * p2 = new T();
对象*p1
是默认初始化的,对象*p2
是值初始化的。
初始化的效果取决于类型T
: 1) 如果T
是基本类型,则默认初始化什么也不做(即对象未初始化),而在这种情况下,值初始化等于零初始化,意味着对象被设置为零。
2) 如果T
是一个聚合(即没有构造函数或析构函数或赋值运算符的类),则每个元素递归地默认或值初始化。
3) 如果T
是类类型并且确实有用户定义的构造函数,那么默认初始化和值初始化都会导致调用默认构造函数。
请注意,具有构造函数的类的成员对象又可以被默认或值初始化:
struct Foo {
int x;
int y;
Foo() : x() { }
};
现在当你说Foo a;
thena
是默认初始化的,所以调用了默认构造函数。这反过来导致a.x
值-,即零初始化,而a.y
保持默认-,即未初始化。
(请注意,实际上不可能对自动对象进行值初始化,尽管在 C++11 中,可以使用大括号初始化来导致值初始化,如.(这与我们的示例中的Foo a{};
行为完全相同,因此Foo a;
第三段。))
这在8.5 Initializers [dcl.init]中处理。
零初始化
5/对类型的对象或引用进行零初始化
T
意味着:— 如果
T
是标量类型 (3.9),则将对象设置为值 0(零),作为整数常量表达式,转换为T
. 如 4.10 中所述,将值为 0 的整型常量表达式转换为指针类型会导致空指针值。— 如果
T
是(可能是 cv 限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都初始化为零并且填充初始化为零位;— 如果
T
是(可能是 cv 限定的)联合类型,则对象的第一个非静态命名数据成员被零初始化,填充被初始化为零位;— 如果
T
是数组类型,则每个元素都初始化为零;— 如果
T
是引用类型,则不执行初始化。
基本上,它等同于 a memset(&obj, 0, sizeof(objt));
,除了它说明空指针的内存表示可能不是 0 值(即使它在语言中由 0 表示)。
// foo.cpp
static char const* p; // p is zero-initialized
// during static initialization
static void init() {
if (!p) { p = new char[500]; } // fine as p has been 0-initialized
}
注意:我个人还是更喜欢使用= nullptr
to initialize p
,只是为了明确意图......
默认初始化
6/默认初始化一个类型的对象
T
意味着:— 如果
T
是(可能是 cv 限定的)类类型(第 9 条),则调用 的默认构造函数(如果没有可访问的默认构造函数T
,则初始化是错误的);T
— 如果
T
是数组类型,则每个元素都是默认初始化的;— 否则,不执行初始化。
如果程序要求对 const 限定类型的对象进行默认初始化
T
,T
则应是具有用户提供的默认构造函数的类类型。
或者基本上,调用默认构造函数,考虑数组,至少对于类。最后一点是对内置插件(例如int
)的警告。那些只是保持原样(里面有垃圾)。
默认初始化是在定义变量但未显式初始化时调用的。初始化列表中未列出的类的属性也会发生这种情况。因此,内置函数的警告对程序员来说非常重要。
int function() {
int a; // <-- a is default-initialized (which means nothing happens...)
return a; // <-- uses a, so technically undefined behavior
}
struct A { int a; A() {} }; // During the call to A::A(),
// A::a is default-initialized (nothing happens...)
缺少显式初始化是 C 的遗留问题。出于优化原因,通常是这样,但如果尝试使用该值,则会导致未定义的行为......
值初始化
7/对类型对象进行值初始化
T
意味着:— 如果
T
是具有用户提供的构造函数(12.1)的(可能是 cv 限定的)类类型(第 9 条),则调用 for 的默认构造函数(如果没有可访问的默认构造函数T
,则初始化是非良构的);T
— 如果
T
是一个(可能是 cv 限定的)非联合类类型,没有用户提供的构造函数,则该对象是零初始化的,如果T
的隐式声明的默认构造函数是非平凡的,则调用该构造函数。— 如果
T
是数组类型,则每个元素都是值初始化的;— 否则,对象被零初始化。
值初始化的对象被认为是已构造的,因此受制于适用于“构造的”对象、“构造函数已完成的对象”等的本国际标准的规定,即使没有为对象的构造函数调用构造函数。初始化。
它是上述两者的混合,这意味着以下语法:
template <typename T> T value() { return T(); }
^~~
提供一个适当初始化的实例,T
说明T
是类类型还是内置类型。模板化代码能够拥有这样一个统一的语法是很重要的。
请注意,使用 C++11,也可以使用T{}
来实现相同的效果(这有助于消除函数的歧义)。