为了统一初始化方式,并且让初始化行为具有确定的效果,C++11 中提出了列表初始化(List-initialization)的概念。

POD 类型即 plain old data 类型,简单来说,是可以直接使用 memcpy 复制的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Foo
{
public:
Foo(int) {}
private:
Foo(const Foo &);
};

int main(void)
{
Foo a1(123);
Foo a2 = 123; //error: 'Foo::Foo(const Foo &)' is private
Foo a3 = { 123 };
Foo a4 { 123 };
int a5 = { 3 };
int a6 { 3 };
return 0;
}

在上例中,a3、a4 使用了新的初始化方式来初始化对象,效果如同 a1 的直接初始化。

a5、a6 则是基本数据类型的列表初始化方式。可以看到,它们的形式都是统一的。

这里需要注意的是,a3 虽然使用了等于号,但它仍然是列表初始化,因此,私有的拷贝构造并不会影响到它。

a4 和 a6 的写法,是 C++98/03 所不具备的。在 C++11 中,可以直接在变量名后面跟上初始化列表,来进行对象的初始化。

这种变量名后面跟上初始化列表方法同样适用于普通数组和 POD 类型的初始化:

1
2
3
4
5
6
7
8
9
10
11
int i_arr[3] { 1, 2, 3 };  //普通数组

struct A
{
int x;
struct B
{
int i;
int j;
} b;
} a { 1, { 2, 3 } }; //POD类型

在初始化时,{}前面的等于号是否书写对初始化行为没有影响。

另外,new 操作符等可以用圆括号进行初始化的地方,也可以使用初始化列表:

1
2
3
int* a = new int { 123 };
double b = double { 12.12 };
int* arr = new int[3] { 1, 2, 3 };

列表初始化还可以直接使用在函数的返回值上:

1
2
3
4
5
6
7
8
9
struct Foo
{
Foo(int, double) {}
};

Foo func(void)
{
return { 123, 321.0 };
}