[英]Are members of structs in a vector initialized with zero in C++?
在C ++中,当我有一个类似的结构
struct myStruct
{
int i;
bool b;
MyClass *myobj;
};
然后我做了一个这样的矢量
std::vector<myStruct> myVector;
我用它来调整矢量大小
myVector.resize(10);
struct的成员是否会用零(包括指针)初始化? 我可以不假设结构成员中可能存在随机数据吗?
在这种特殊情况下,答案是YES,因为std::vector::resize()
的属性:
If the current size is less than count, additional elements are appended and initialized with copies of value. (until C++11)
If the current size is less than count, (since C++11)
1) additional value-initialized elements are appended
2) additional copies of value are appended
对于正常情况,例如myStruct s
,答案将为NO ,这将使它们( si, s.bool, s.myobj
)具有不确定的值 。
如果您仍希望按预期初始化它们,请为结构创建一个构造函数:
struct myStruct {
int i;
bool b;
MyClass *myobj;
myStruct():i(0),b(false),myobj(NULL) { } // <- set them here by default
};
我其实乞求不同。 在这种特殊情况下 ,标准似乎保证对象将被零初始化。 (以下所有标准参考均为N3936。)
在这种情况下, vector::resize
被指定为在序列中附加10个“默认插入元素”(§23.3.6.3[vector.capacity] / p12)。
默认插入又定义为(§23.2.1[container.requirements.general] / p14; X
是容器的类型; m
是类型A
的左值,它是容器的allocator_type
):
如果通过评估表达式初始化
X
则默认插入X
的元素allocator_traits<A>::construct(m, p)
其中
p
是X
分配的元素的未初始化存储的地址。
由于编写代码使用默认分配器, allocator_traits::construct
调用只是在std::allocator<myStruct>
(第20.7.8.2节[allocator.traits.members] / p5)的实例上调用construct(p)
,指定为(§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()
。
该标准规定新的初始值设定项 ,如上面的放置新表达式中的()
,将根据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
一个默认的构造函数,该构造函数明确地将其成员归零。
是的,在这个特殊情况下,结构将初始化为零。 原因是在STL中实现了resize()
方法。 新元素是默认构造的:
void resize(size_type __new_size) {
resize(__new_size, value_type());
}
value_type()
导致零初始化。
#include <cstdio>
struct foo {
int i;
int j;
void *k;
};
void test(const foo& fooinst) {
printf("%d\n",fooinst.i);
}
main() {
test(foo());
}
这是生成的g ++反汇编的相关部分。 注意在调用之前结构成员的显式零初始化。
test.cpp **** test(foo());
56 .loc 1 14 0
57 002d C745F000 movl $0, -16(%rbp)
57 000000
58 0034 C745F400 movl $0, -12(%rbp)
58 000000
59 003b 48C745F8 movq $0, -8(%rbp)
59 00000000
60 0043 488D45F0 leaq -16(%rbp), %rax
61 0047 4889C7 movq %rax, %rdi
62 004a E8000000 call _Z4testRK3foo
在值vector
被初始化与所述的默认构造(或值初始化) struct
,在这种情况下myStruct
。
struct
没有默认构造函数,因此将使用编译器生成的构造函数。 在这种情况下,它会使myStruct
的对象myStruct
未初始化状态。
不,通常,您不能假设数据将初始化为零。
这个特殊情况( .resize()
)正在选择有价值初始化的情况,并且C ++ 03和C ++ 11也有一些变化(其他答案提供了更多细节)。
最好的建议仍然是 ,要做的是添加适当初始化struct
的默认构造struct
。
调用结构的ctor。 由于您没有指定一个(并且您可以,甚至对于结构),默认情况下,使用do-nothing ctor。 默认的ctor不会清除成员。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.