原文:C值初始化,默认初始化,以及其他初始化类型的区别?
     C11 带来的新特性(2)-统一初始化(Uniform Initialization)
在C11之前,初始化没有一个统一的写法,对象的初始化方式是不同的(小括号,大括号,赋值),C11努力创造一个统一的初始化方式,其语法是使用{}std::initializer_list。我们调用的一般形式是:

  1. [new] T [object] {arg1, arg2, ...};

list initialization & aggregate initialization

从简单情况来说,list initialization我们并不陌生,本质上就是:

  • 如果T是aggregate类型,list中的参数对object成员逐个初始化,若list参数个数小于T成员个数,剩余成员调用value initialization
  • 如果T不是aggregate类型,编译器查找最匹配list参数的T的构造函数。

通过一个例子看看具体细节:

  1. std::vector<int> v{1, 2, 3};
  • 首先,参数列表{1, 2, 3}转换为std::initializer_list
    从stl的源码中可以看出initializer_list带参数的构造函数是一个私有函数,只能通过编译器调用。
  1. private:
  2. iterator _M_array;
  3. size_type _M_len;
  4. // The compiler can call a private constructor.
  5. constexpr initializer_list(const_iterator __a, size_type __l)
  6. : _M_array(__a), _M_len(__l) { }
  • 其次,使用std::initializer对象来初始化std::vector的构造函数。
  1. vector(initializer_list<value_type> __l,
  2. const allocator_type& __a = allocator_type())
  3. : _Base(__a)
  4. {
  5. _M_range_initialize(__l.begin(), __l.end(),
  6. random_access_iterator_tag());
  7. }

value initialization

如果在list initialization行驶中,没有任何参数args,也就是:

  1. [new] T [object] {};

值初始化一般有三种处理方式:

  • 如果T有用户定义的缺省构造函数,直接调用;
  • 如果T有编译器生成的缺省构造函数,先0值初始化再调用;
  • 如果T根本不是类,直接0值初始化。

default initialization

  1. [new] T [object];

缺省初始化除了在值初始化过程中可能进行之外,也可以以上面形式单独进行。这种初始化的独特地方在于,如果T是非class类型,则给出非确定值(不赋值),比如:

  1. int i; //i值未定义
  2. int j{}; //j=0
  3. int *p; //p值未定义
  4. int *q{}; //q=nullptr

zero initialization

0值初始化除了在值初始化过程中可能进行之外,也可以单独作用于静态(或者线程局部)变量:

  1. static T object;

总结

理解的要点在于,list中的参数要么按构造函数的参数声明顺序,要么按aggregate类型成员声明顺序,逐个赋值。当某些成员没有被这样显示给定值时,进行广义缺省初始化(value initialization):或调用缺省构造函数,或赋0值。