值初始化
出自 cppreference.com
這是當物件以空初始化器(empty initializer)建構時所執行的初始化。
目錄 |
[編輯] 語法
T () |
(1) | ||||||||
new T () |
(2) | ||||||||
Class::Class(...) : member () { ... } |
(3) | ||||||||
T object {}; |
(4) | (C++11 起) | |||||||
T {} |
(5) | (C++11 起) | |||||||
new T {} |
(6) | (C++11 起) | |||||||
Class::Class(...) : member {} { ... } |
(7) | (C++11 起) | |||||||
[編輯] 解釋
在以下情況中會執行值初始化:
1,5) 當創建一個無名臨時物件,且其初始化器由一對空圓括號或花括號(C++11 起)組成時;
4) 當具名物件(自動、靜態或執行緒局部)宣告時,其初始化器由一對花括號組成時。
在所有情況下,如果使用空的圓括號對 {} 且 T 是聚合型別(aggregate type),則會執行聚合初始化而非值初始化。
|
如果 |
(C++11 起) |
值初始化的效果如下:
- 若
T為(可能含有 cv 限定符的)類別型別:
- 否則,若
T是陣列型別,則陣列的每個元素都會進行值初始化。 - 否則,該物件會進行零初始化。
[編輯] 附註
語法 T object(); 並不會初始化物件;它宣告了一個不帶參數且回傳 T 的函式。在 C++11 之前,對具名變數進行值初始化的方式是 T object = T();,這會值初始化一個臨時物件,然後拷貝初始化該變數:大多數編譯器在此情況下會省略拷貝。
參考不能進行值初始化。
如函式風格轉型所述,若 T 為陣列型別,語法 T() (1) 是禁止的,而 T{} (5) 則是允許的。
所有標準容器(std::vector、std::list 等)在以單一 size_type 參數建構或透過呼叫 resize() 擴增時,會對其元素進行值初始化,除非其配置器(allocator)自訂了 construct 的行為。
[編輯] 範例
執行此程式碼
#include <cassert> #include <iostream> #include <string> #include <vector> struct T1 { int mem1; std::string mem2; virtual void foo() {} // make sure T1 is not an aggregate }; // implicit default constructor struct T2 { int mem1; std::string mem2; T2(const T2&) {} // user-provided copy constructor }; // no default constructor struct T3 { int mem1; std::string mem2; T3() {} // user-provided default constructor }; std::string s{}; // class => default-initialization, the value is "" int main() { int n{}; // scalar => zero-initialization, the value is 0 assert(n == 0); double f = double(); // scalar => zero-initialization, the value is 0.0 assert(f == 0.0); int* a = new int[10](); // array => value-initialization of each element assert(a[9] == 0); // the value of each element is 0 T1 t1{}; // class with implicit default constructor => assert(t1.mem1 == 0); // t1.mem1 is zero-initialized, the value is 0 assert(t1.mem2 == ""); // t1.mem2 is default-initialized, the value is "" // T2 t2{}; // error: class with no default constructor T3 t3{}; // class with user-provided default constructor => std::cout << t3.mem1; // t3.mem1 is default-initialized to indeterminate value assert(t3.mem2 == ""); // t3.mem2 is default-initialized, the value is "" std::vector<int> v(3); // value-initialization of each element assert(v[2] == 0); // the value of each element is 0 std::cout << '\n'; delete[] a; }
可能輸出
42
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯應用於之前的 C++ 標準。
| DR | 應用於 | 出版時的行為 | 正確的行為 |
|---|---|---|---|
| CWG 178 | C++98 | 原本沒有值初始化;空初始化器呼叫預設 初始化(雖然 new T() 也執行零初始化) |
空初始化器呼叫 值初始化 |
| CWG 543 | C++98 | 對於沒有任何使用者提供建構函式的類別物件, 值初始化等同於值初始化每個子物件(這不需要 對具有使用者提供預設建構函式的成員進行 零初始化) |
零初始化 整個物件, 然後呼叫 預設建構函式 |
| CWG 1301 | C++11 | 具有被刪除的預設建構函式之等位體(union) 的值初始化會導致零初始化 |
它們是 預設初始化 |
| CWG 1368 | C++98 | 任何使用者提供的建構函式都會導致 零初始化被跳過 |
只有使用者提供的 預設建構函式 才會跳過零初始化 |
| CWG 1502 | C++11 | 值初始化一個沒有使用者提供 預設建構函式的等位體僅會對該 物件進行零初始化,儘管有預設成員初始化器 |
執行預設 初始化在 零初始化之後 |
| CWG 1507 | C++98 | 對於沒有任何使用者提供建構函式的類別物件, 使用者提供的建構函式未檢查預設建構函式 的有效性(當後者是平凡的時) |
平凡的有效性 預設建構函式 會被檢查 |
| CWG 2820 | C++98 | 在零初始化之後進行的預設初始化 需要一個非平凡的建構函式 |
不再需要 |
| CWG 2859 | C++98 | 類別物件的值初始化可能涉及 零初始化,即使預設初始化 並沒有實際選擇使用者提供的建構函式 |
不存在 零初始化之後 在此情況下 |