我实际上不敢苟同。 在这种特殊情况下,该标准似乎保证对象将被零初始化。 (以下所有标准参考均为 N3936。)
vector::resize 在这种情况下被指定附加 10 个“默认插入的元素到序列”(§23.3.6.3 [vector.capacity]/p12)。
默认插入又被定义为 (§23.2.1 [container.requirements.general]/p14;X 是容器的类型;m 是 A 类型的左值,这是容器的allocator_type):
X 的元素如果通过求值初始化,则默认插入
表达方式
allocator_traits<A>::construct(m, p)
其中p 是X 中分配的元素的未初始化存储地址。
由于编写的代码使用默认分配器,allocator_traits::construct 调用只是在std::allocator<myStruct> 的实例上调用construct(p)(§20.7.8.2 [allocator.traits.members]/p5),它被指定为(§20.7.9.1 [allocator.members]/p12)
template <class U, class... Args>
void construct(U* p, Args&&... args);
12 效果:::new((void *)p) U(std::forward<Args>(args)...)
由于construct(p)的参数包为空,所以construct()调用的效果是::new((void *)p) myStruct()。
标准规定,new-initializers,就像上面放置 new 表达式中的 (),将被解释为“根据 8.5 的初始化规则进行直接初始化”(§5.3. 4 [expr.new]/p17)。反过来,第 8.5 节 [dcl.init]/p11 指定“初始化器为空括号集的对象,即 (),应进行值初始化。”
值初始化被指定为 (§8.5 [dcl.init]/p8)
对T 类型的对象进行值初始化意味着:
- 如果
T 是(可能是 cv 限定的)类类型(第 9 条),没有默认构造函数 (12.1) 或默认构造函数是
用户提供或删除,则对象默认初始化;
- 如果
T 是一个(可能是 cv 限定的)类类型,没有用户提供或删除的默认值
构造函数,则对象被零初始化,语义约束为
检查默认初始化,如果 T 有一个非平凡的默认值
构造函数,对象是默认初始化的;
- 如果
T是数组类型,那么每个元素都是值初始化的;
- 否则,对象被零初始化。
在这种情况下,myStruct 是“没有用户提供或删除的默认构造函数的类类型”,这意味着它匹配执行零初始化的第二个要点。因此,myStruct 类型的对象的值初始化意味着该对象将被零初始化。
但是,请注意这里的规则非常复杂,自动零初始化的路径非常脆弱。例如,如果你给myStruct 一个像myStruct() { } 这样的默认构造函数,那么这是一个用户提供的默认构造函数,这意味着它将匹配值初始化的第一个项目符号而不是第二个,这反过来意味着它不会被零初始化。此外,如果您的 vector 使用自定义分配器,这也可能不起作用,因为它的 construct() 可能与默认分配器的语义不同。
因此,最好给myStruct 一个默认构造函数,将其成员显式归零。