簡體   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