在C ++中,当我有一个像
这样的结构时struct myStruct
{
int i;
bool b;
MyClass *myobj;
};
然后我制作了这个
的矢量std::vector<myStruct> myVector;
我用
调整了矢量大小myVector.resize(10);
结构的成员是否会用零(包括指针)初始化?我可以不假设结构的成员中可能存在随机数据吗?
答案 0 :(得分:5)
在这种特殊情况下,由于std::vector::resize()
的属性,答案为 YES :
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
,这会让他们(s.i, s.bool, s.myobj
)留下不确定的值。
如果您仍希望按预期初始化它们,请为结构创建构造函数:
struct myStruct {
int i;
bool b;
MyClass *myobj;
myStruct():i(0),b(false),myobj(NULL) { } // <- set them here by default
};
答案 1 :(得分:4)
我其实乞求不同。 在这种特殊情况下,标准似乎保证对象将被零初始化。 (以下所有标准参考均为N3936。)
在这种情况下, vector::resize
被指定为在序列中附加10个“默认插入元素”(§23.3.6.3[vector.capacity] / p12)。
默认插入依次定义为(§23.2.1[container.requirements.general] / p14; X
是容器的类型; m
是类型{{1}的左值},这是容器的A
):
allocator_type
的元素如果通过评估初始化,则默认插入 表达式X
其中
allocator_traits<A>::construct(m, p)
是p
内分配的元素的未初始化存储的地址。
由于编写代码使用默认分配器,X
调用只调用allocator_traits::construct
实例上的construct(p)
(§20.7.8.2[allocator.traits.members] / p5 ),指定为(§20.7.9.1[allocator.members] / p12)
std::allocator<myStruct>
12 效果:
template <class U, class... Args> void construct(U* p, Args&&... args);
由于::new((void *)p) U(std::forward<Args>(args)...)
的参数包为空,因此construct(p)
来电的效果为construct()
。
该标准规定 new-initializers ,如上面的placement new表达式中的::new((void *)p) myStruct()
,将根据8.5的初始化规则进行解释,以便直接初始化“(§ 5.3.4 [expr.new] / p17)。反过来,§8.5[dcl.init] / p11指定“一个对象,其初始化程序是一组空的括号,即()
,应进行值初始化。”
值初始化指定为(§8.5[dcl.init] / p8)
对
()
类型的对象进行值初始化意味着:
- 如果
T
是一个(可能是cv限定的)类类型(第9条),没有默认构造函数(12.1)或者是默认构造函数 用户提供或删除,然后该对象被默认初始化;- 如果
T
是(可能是cv限定的)类类型,没有用户提供或删除的默认值 构造函数,然后对象是零初始化和语义约束 检查默认初始化,如果T具有非平凡的默认值 构造函数,该对象是默认初始化的;- 如果
T
是数组类型,则每个元素都是值初始化的;- 否则,该对象为零初始化。
在这种情况下,T
是“没有用户提供或删除的默认构造函数的类类型”,这意味着它匹配执行零初始化的第二个项目符号点。因此,类型myStruct
的对象的值初始化意味着该对象将被零初始化。
但请注意,这里的规则非常复杂,自动归零初始化的路径非常脆弱。例如,如果给myStruct
一个默认构造函数,如myStruct
,那么这是一个用户提供的默认构造函数,这意味着它将匹配值初始化的第一个项目符号而不是第二个项目符号,转意味着它不会被零初始化。此外,如果myStruct() { }
使用自定义分配器,这也可能不起作用,因为它的vector
可能具有与默认分配器不同的语义。
因此,最好给construct()
一个显式地将其成员归零的默认构造函数。
答案 2 :(得分:2)
是的,在这个特殊情况下,结构将初始化为零。原因是在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
答案 3 :(得分:1)
vector
中的值是使用struct
的默认构造函数(或初始值)初始化的,在本例中为myStruct
。
struct
没有默认构造函数,因此将使用编译器生成的构造函数。在这种情况下,它会保留myStruct
未初始化的对象。
不,通常,您不能假设数据初始化为零。
这种特殊情况(.resize()
)正在选择有价值初始化的情况,并且C ++ 03和C ++ 11也有一些变化(其他答案提供了更多细节)。
最好的建议仍然是,要做的是添加适当初始化struct
的默认构造函数。
答案 4 :(得分:0)
调用结构的ctor。由于您没有指定一个(并且您可以,甚至对于结构),默认情况下,使用do-nothing ctor。默认的ctor不会清除成员。