原文:C++值初始化,默认初始化,以及其他初始化类型的区别?
C++11 带来的新特性(2)-统一初始化(Uniform Initialization)
在C++11之前,初始化没有一个统一的写法,对象的初始化方式是不同的(小括号,大括号,赋值),C++11努力创造一个统一的初始化方式,其语法是使用{}
和std::initializer_list
。我们调用的一般形式是:
[new] T [object] {arg1, arg2, ...};
list initialization & aggregate initialization
从简单情况来说,list initialization我们并不陌生,本质上就是:
- 如果T是aggregate类型,list中的参数对object成员逐个初始化,若list参数个数小于T成员个数,剩余成员调用value initialization
- 如果T不是aggregate类型,编译器查找最匹配list参数的T的构造函数。
通过一个例子看看具体细节:
std::vector<int> v{1, 2, 3};
- 首先,参数列表
{1, 2, 3}
转换为std::initializer_list
。
从stl的源码中可以看出initializer_list
带参数的构造函数是一个私有函数,只能通过编译器调用。
private:
iterator _M_array;
size_type _M_len;
// The compiler can call a private constructor.
constexpr initializer_list(const_iterator __a, size_type __l)
: _M_array(__a), _M_len(__l) { }
- 其次,使用
std::initializer
对象来初始化std::vector
的构造函数。
vector(initializer_list<value_type> __l,
const allocator_type& __a = allocator_type())
: _Base(__a)
{
_M_range_initialize(__l.begin(), __l.end(),
random_access_iterator_tag());
}
value initialization
如果在list initialization行驶中,没有任何参数args,也就是:
[new] T [object] {};
值初始化一般有三种处理方式:
- 如果T有用户定义的缺省构造函数,直接调用;
- 如果T有编译器生成的缺省构造函数,先0值初始化再调用;
- 如果T根本不是类,直接0值初始化。
default initialization
[new] T [object];
缺省初始化除了在值初始化过程中可能进行之外,也可以以上面形式单独进行。这种初始化的独特地方在于,如果T是非class类型,则给出非确定值(不赋值),比如:
int i; //i值未定义
int j{}; //j=0
int *p; //p值未定义
int *q{}; //q=nullptr
zero initialization
0值初始化除了在值初始化过程中可能进行之外,也可以单独作用于静态(或者线程局部)变量:
static T object;
总结
理解的要点在于,list中的参数要么按构造函数的参数声明顺序,要么按aggregate类型成员声明顺序,逐个赋值。当某些成员没有被这样显示给定值时,进行广义缺省初始化(value initialization):或调用缺省构造函数,或赋0值。
- list initialization (since C++11)
- aggregate initialization 这是list initialization对aggregate类型的特例
- value initialization 值初始化
- default initialization 缺省初始化
- zero initialization 0值初始化