简体   繁体   English

向量中的结构成员是否在C ++中初始化为零?

[英]Are members of structs in a vector initialized with zero in C++?

In C++, when I have a struct like 在C ++中,当我有一个类似的结构

struct myStruct
{
  int i;
  bool b;
  MyClass *myobj;
};

and I then make a vector of this 然后我做了一个这样的矢量

std::vector<myStruct> myVector;

and I resize the vector with 我用它来调整矢量大小

myVector.resize(10);

Will the struct's members be initialized with zero's (including the pointer)? struct的成员是否会用零(包括指针)初始化? Can I not assume that and might there be random data in the struct's members? 我可以不假设结构成员中可能存在随机数据吗?

In this particular case, the answer is YES because of std::vector::resize() 's properties: 在这种特殊情况下,答案是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

The answer will be NO for normal cases, eg myStruct s , this will leave them ( si, s.bool, s.myobj ) with indeterminate values . 对于正常情况,例如myStruct s ,答案将为NO ,这将使它们( si, s.bool, s.myobj )具有不确定的值

If you still want them to be initialized as expected, create a constructor for the struct: 如果您仍希望按预期初始化它们,请为结构创建一个构造函数:

struct myStruct {
    int i;
    bool b;
    MyClass *myobj;

    myStruct():i(0),b(false),myobj(NULL) { }  // <- set them here by default
};

I actually beg to differ. 我其实乞求不同。 In this particular case , the standard appears to guarantee that the objects will be zero-initialized. 在这种特殊情况下 ,标准似乎保证对象将被零初始化。 (All standard references below are to N3936.) (以下所有标准参考均为N3936。)

vector::resize in this case is specified to append 10 "default-inserted elements to the sequence" (§23.3.6.3 [vector.capacity]/p12). 在这种情况下, vector::resize被指定为在序列中附加10个“默认插入元素”(§23.3.6.3[vector.capacity] / p12)。

Default-insertion is in turn defined as (§23.2.1 [container.requirements.general]/p14; X is the container's type; m is an lvalue of type A , which is the container's allocator_type ): 默认插入又定义为(§23.2.1[container.requirements.general] / p14; X是容器的类型; m是类型A的左值,它是容器的allocator_type ):

An element of X is default-inserted if it is initialized by evaluation of the expression 如果通过评估表达式初始化X则默认插入X的元素

 allocator_traits<A>::construct(m, p) 

where p is the address of the uninitialized storage for the element allocated within X . 其中pX分配的元素的未初始化存储的地址。

Since as written the code uses the default allocator, the allocator_traits::construct call simply calls construct(p) on an instance of std::allocator<myStruct> (§20.7.8.2 [allocator.traits.members]/p5), which is specified as (§20.7.9.1 [allocator.members]/p12) 由于编写代码使用默认分配器, 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 Effects : ::new((void *)p) U(std::forward<Args>(args)...) 12 效果 ::new((void *)p) U(std::forward<Args>(args)...)

Since the parameter pack is empty for construct(p) , the effect of the construct() call is ::new((void *)p) myStruct() . 由于参数包对于construct(p)是空的,所以construct()调用的效果是::new((void *)p) myStruct()

The standard provides that new-initializers , like the () in the placement new expression above, are to be interpreted "according to the initialization rules of 8.5 for direct initialization" (§5.3.4 [expr.new]/p17). 该标准规定新的初始值设定项 ,如上面的放置新表达式中的() ,将根据8.5的初始化规则进行解释,以进行直接初始化(§5.3.4[expr.new] / p17)。 In turn, §8.5 [dcl.init]/p11 specifies that "An object whose initializer is an empty set of parentheses, ie, () , shall be value-initialized." 反过来,§8.5[dcl.init] / p11指定“初始值为空集括号的对象,即() ,应进行值初始化。”

Value-initialization is specified as (§8.5 [dcl.init]/p8) 值初始化指定为(§8.5[dcl.init] / p8)

To value-initialize an object of type T means: 对值类型T的对象进行值初始化意味着:

  • if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized; 如果T是一个(可能是cv限定的)类类型(第9条),没有默认构造函数(12.1)或者是用户提供或删除的默认构造函数,那么该对象是默认初始化的;
  • if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized; 如果T是一个(可能是cv限定的)类类型而没有用户提供或删除的默认构造函数,那么该对象是零初始化的,并且检查默认初始化的语义约束,如果T有一个非平凡的默认构造函数,该对象是默认初始化的;
  • if T is an array type, then each element is value-initialized; 如果T是数组类型,那么每个元素都是值初始化的;
  • otherwise, the object is zero-initialized. 否则,该对象被零初始化。

In this case, myStruct is a "class type without a user-provided or deleted default constructor", which means it matches the second bullet point, which performs zero-initialization. 在这种情况下, myStruct是“没有用户提供或删除的默认构造函数的类类型”,这意味着它匹配执行零初始化的第二个项目符号点。 Thus, value-initialization for an object of type myStruct means the object will be zero-initialized. 因此, myStruct类型的对象的值初始化意味着该对象将被零初始化。

However, note that the rules here are quite convoluted, and the path to automatic zero-initialization is quite fragile. 但请注意,这里的规则非常复杂,自动零初始化的路径非常脆弱。 For example, if you give myStruct a default constructor like myStruct() { } , then that's a user-provided default constructor, which means that it will match the first bullet point for value initialization instead of the second, which in turn means that it won't be zero-initialized. 例如,如果你给myStruct一个默认的构造函数,比如myStruct() { } ,那么这是一个用户提供的默认构造函数,这意味着它将匹配值初始化的第一个项目符号而不是第二项,这反过来意味着它不会被零初始化。 Moreover, this may also not work if your vector uses a custom allocator, as its construct() might have different semantics than that of the default allocator. 此外,如果您的vector使用自定义分配器,这也可能不起作用,因为它的construct()可能具有与默认分配器不同的语义。

Therefore, it is probably better to give myStruct a default constructor that explicitly zeroes its members. 因此,最好给myStruct一个默认的构造函数,该构造函数明确地将其成员归零。

Yes the structs will be initialised to zero IN THIS PARTICULAR CASE. 是的,在这个特殊情况下,结构将初始化为零。 The reason is the implementation of the resize() method in the STL. 原因是在STL中实现了resize()方法。 New elements are default-constructed: 新元素是默认构造的:

void resize(size_type __new_size) {
    resize(__new_size, value_type());
}

value_type() results in zero initialisation. value_type()导致零初始化。

test evidence 测试证据

#include <cstdio>

struct foo {
  int i;
  int j;
  void *k;
};

void test(const foo& fooinst) {
  printf("%d\n",fooinst.i);
}

main() {
  test(foo());
}

Here's the relevant part of the resulting g++ disassembly. 这是生成的g ++反汇编的相关部分。 Note the explicit zero initialisation of the struct members before the call. 注意在调用之前结构成员的显式零初始化。

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

The values in the vector are initialised with the default constructor (or value initialised) of the struct , in this case myStruct . 在值vector被初始化与所述的默认构造(或值初始化) struct ,在这种情况下myStruct

The struct has no default constructor, so the compiler generated one will be used. struct没有默认构造函数,因此将使用编译器生成的构造函数。 In this case it leaves the objects of myStruct uninitialised. 在这种情况下,它会使myStruct的对象myStruct未初始化状态。

No, in general, you cannot assume the data will be zero initialised. 不,通常,您不能假设数据将初始化为零。

This particular case (the .resize() ) is picking at a situation where there is value initialisation and there has been some change from C++03 and C++11 (other answers provide more detail). 这个特殊情况( .resize() )正在选择有价值初始化的情况,并且C ++ 03和C ++ 11也有一些变化(其他答案提供了更多细节)。

Best advice remains , thing to do is add the default constructor that initialises the struct appropriately. 最好的建议仍然是 ,要做的是添加适当初始化struct的默认构造struct

The ctor for the struct is called. 调用结构的ctor。 Since you don't specify one (and you can, even for a struct), a default, do-nothing ctor is used. 由于您没有指定一个(并且您可以,甚至对于结构),默认情况下,使用do-nothing ctor。 The default ctor does not clear the members. 默认的ctor不会清除成员。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM