3.3.1 定义和初始化vector对象(2)
这里的10是用来说明如何初始化vector对象的,我们用它的本意是想创建含有10个值初始化了的元素的vector对象,而非把数字10"拷贝"到vector中。因此,此时不宜使用拷贝初始化,7.5.4节(第296页)将对这一点做更详细的介绍。
列表初始值还是元素数量?
在某些情况下,初始化的真实含义依赖于传递初始值时用的是花括号还是圆括号。例如,用一个整数来初始化vector<int>时,整数的含义可能是vector对象的容量也可能是元素的值。类似的,用两个整数来初始化vector<int>时,这两个整数可能一个是vector对象的容量,另一个是元素的初值,也可能它们是容量为2的vector对象中两个元素的初值。通过使用花括号或圆括号可以区分上述这些含义:
- vector<int> v1(10); // v1有10个元素,每个的值都是0
- vector<int> v2{10}; // v2有1个元素,该元素的值是10
- vector<int> v3(10, 1); // v3有10个元素,每个的值都是1
- vector<int> v4{10, 1}; // v4有2个元素,值分别是10和1
如果用的是圆括号,可以说提供的值是用来构造(construct)vector对象的。例如,v1的初始值说明了vector对象的容量;v3的两个初始值则分别说明了vector对象的容量和元素的初值。
如果用的是花括号,可以表述成我们想列表初始化(list initialize)该vector对象。也就是说,初始化过程会尽可能地把花括号内的值当成是元素初始值的列表来处理,只有在无法执行列表初始化时才会考虑其他初始化方式。在上例中,给v2和v4提供的初始值都能作为元素的值,所以它们都会执行列表初始化,vector对象v2包含一个元素而vector对象v4包含两个元素。
另一方面,如果初始化时使用了花括号的形式但是提供的值又不能用来列表初始化,就要考虑用这样的值来构造vector对象了。例如,要想列表初始化一个含有string对象的vector对象,应该提供能赋给string对象的初值。此时不难区分到底是要列表初始化vector对象的元素还是用给定的容量值来构造vector对象:
- vector<string> v5{"hi"}; // 列表初始化:v5有一个元素
- vector<string> v6("hi"); // 错误:不能使用字符串字面值构建vector对象
- vector<string> v7{10}; // v7有10个默认初始化的元素
- vector<string> v8{10, "hi"}; // v8有10个值为"hi"的元素
尽管在上面的例子中除了第二条语句之外都用了花括号,但其实只有v5是列表初始化。要想列表初始化vector对象,花括号里的值必须与元素类型相同。显然不能用int初始化string对象,所以v7和v8提供的值不能作为元素的初始值。确认无法执行列表初始化后,编译器会尝试用默认值初始化vector对象。
3.3.1节练习
练习3.12:下列vector对象的定义有不正确的吗?如果有,请指出来。对于正确的,描述其执行结果;对于不正确的,说明其错误的原因。
(a) vector<vector<int>> ivec;
(b) vector<string> svec = ivec;
(c) vector<string> svec(10, "null");
练习3.13:下列的vector对象各包含多少个元素?这些元素的值分别是多少?
(a) vector<int> v1; (b) vector<int> v2(10);
(c) vector<int> v3(10, 42); (d) vector<int> v4{10};
(e) vector<int> v5{10, 42}; (f) vector<string> v6{10};
(g) vector<string> v7{10, "hi"};