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