值初始化
來自 cppreference.com
這是當物件以一個空的初始化器構造時所進行的初始化。
目錄 |
[編輯] 語法
T () |
(1) | ||||||||
new T () |
(2) | ||||||||
類:: 類( ...) : 成員 () { ... } |
(3) | ||||||||
T 物件 {}; |
(4) | (C++11 起) | |||||||
T {} |
(5) | (C++11 起) | |||||||
new T {} |
(6) | (C++11 起) | |||||||
類:: 類( ...) : 成員 {} { ... } |
(7) | (C++11 起) | |||||||
[編輯] 解釋
值初始化在以下情形進行
1,5) 當以一個由空括號或花括號(C++11 起)組成的初始化器建立無名臨時物件時;
4) 當宣告具名物件(自動、靜態或執行緒區域性)時,其初始化器由一對花括號組成。
在所有情況下,若使用空的花括號對 {}
且 T
為聚合型別,則進行聚合初始化,而非值初始化。
若 |
(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() 擴容時,都會對其元素進行值初始化,除非它們的分配器自定義了 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++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
CWG 178 | C++98 | 沒有值初始化;空初始化器呼叫預設 初始化(儘管 new T() 也進行零初始化) |
空初始化器呼叫 值初始化 |
CWG 543 | C++98 | 對於沒有任何使用者提供的建構函式的類物件,值初始化 等同於值 初始化每個子物件(這不一定會零 初始化一個帶有使用者提供預設建構函式的成員) |
零初始化 整個物件, 然後呼叫 預設建構函式 |
CWG 1301 | C++11 | 對具有已刪除預設建構函式的聯合體進行值初始化 會導致零初始化 |
它們是 預設初始化 |
CWG 1368 | C++98 | 任何使用者提供的建構函式都會導致 跳過零初始化 |
只有使用者提供的 預設建構函式 會跳過零初始化 |
CWG 1502 | C++11 | 對沒有使用者提供的預設建構函式的聯合體進行值初始化 只對該物件進行零初始化, 儘管存在預設成員初始化器 |
在零初始化後 進行預設 初始化 |
CWG 1507 | C++98 | 對於沒有任何使用者提供的建構函式的類物件,值初始化 當預設建構函式是平凡的時候, 使用者提供的建構函式不會檢查其有效性 |
平凡的有效性 預設建構函式 被檢查 |
CWG 2820 | C++98 | 零初始化之後的預設 初始化需要一個非平凡的建構函式 |
未要求 |
CWG 2859 | C++98 | 類物件的值初始化可能涉及 零初始化,即使預設初始化 實際上並未選擇使用者提供的建構函式 |
沒有 初始化 在這種情況下 |