3种类型的初始化

时间:2012-02-18 16:12:39

标签: c++ initialization value-initialization

  

可能重复:
  What do the following phrases mean in C++: zero-, default- and value-initialization?

今天我开始了解C ++中有三种类型的初始化:

  • 零初始化
  • 默认初始化
  • 价值初始化

我用谷歌搜索过但我发现没有令人满意的结果。我得到的只是一些标准。到目前为止我所理解的是:在值初始化的情况下,数据成员在某些情况下可以获得等于零的值。

请用例子详细说明(标准)。另外,请不要只提供标准中的文字。

谢谢

2 个答案:

答案 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{}来实现相同的效果(这有助于消除函数的歧义)。