繁体   English   中英

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

[英]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) 

其中pX分配的元素的未初始化存储的地址。

由于编写代码使用默认分配器, 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.

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