可能重复:
What do the following phrases mean in C++: zero-, default- and value-initialization?
今天我开始了解C ++中有三种类型的初始化:
我用谷歌搜索过但我发现没有令人满意的结果。我得到的只是一些标准。到目前为止我所理解的是:在值初始化的情况下,数据成员在某些情况下可以获得等于零的值。
请用例子详细说明(标准)。另外,请不要只提供标准中的文字。
谢谢
答案 0 :(得分:6)
初始化类型是指语言语法。以下是两个例子:
T * p1 = new T;
T * p2 = new T();
对象*p1
是默认初始化的,对象*p2
是值初始化的。
初始化的效果取决于类型T
:1)如果T
是基础,则默认初始化不执行任何操作(即对象保留未初始化 ),在这种情况下,值初始化等于零初始化,意味着对象设置为零。
2)如果T
是一个聚合(即没有构造函数或析构函数或赋值运算符的类),则每个元素都是递归默认值或值初始化。
3)如果T
是class-type并且具有用户定义的构造函数,则default-和value-initialization都会导致对默认构造函数的调用。
请注意,具有构造函数的类的成员对象可以依次进行默认值或值初始化:
struct Foo {
int x;
int y;
Foo() : x() { }
};
现在,当您说Foo a;
时,a
被默认初始化,因此调用默认构造函数。这反过来导致a.x
为值 - 即零初始化,而a.y
保持默认值,即未初始化。
(注意,实际上不可能对自动对象进行值初始化,但在C ++ 11中,可以使用大括号初始化来进行值初始化,如Foo a{};
中所示。(这恰好表示与我们示例中的Foo a;
相同,在第三段之后。))
答案 1 :(得分:3)
这在 8.5 Initializers [dcl.init] 中处理。
零初始化
5 / 要对
T
类型的对象或引用进行零初始化,意味着:- 如果
T
是标量类型(3.9),则将对象设置为值0(零),作为整数常量表达式,转换为T
。如4.10中所述,将值为0的整型常量表达式转换为指针类型会导致空指针 值。- 如果
T
是一个(可能是cv限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化的,并且填充初始化为零位;- 如果
T
是一个(可能是cv限定的)联合类型,则该对象的第一个非静态命名数据成员为零初始化,并且填充初始化为零位;- 如果
T
是数组类型,则每个元素都是零初始化的;- 如果
T
是引用类型,则不执行初始化。
基本上,它等同于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
来初始化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节),则调用T
的默认构造函数(并初始化)如果T
没有可访问的默认构造函数,则格式错误;- 如果
T
是一个(可能是cv限定的)非联合类类型而没有用户提供的构造函数,那么该对象是零初始化的,如果T
是隐式声明的默认构造函数是非平凡的,该构造函数被调用。- 如果
T
是数组类型,则每个元素都是值初始化的;- 否则,该对象为零初始化。
值初始化的对象被视为构造,因此受本国际标准的规定适用于“构造”对象,“构造函数已完成的对象”等,即使没有调用构造函数也是如此用于对象的初始化。
它是上述两者的混合,意味着以下语法:
template <typename T> T value() { return T(); }
^~~
提供T
的适当初始化实例,T
是类类型还是内置类型。模板化代码能够拥有这样统一的语法非常重要。
请注意,使用C ++ 11,也可以使用T{}
来实现相同的效果(这有助于消除函数的歧义)。