預設初始化
來自 cppreference.com
這是物件在沒有初始化器的情況下構造時執行的初始化。
目錄 |
[編輯] 語法
T 物件 ; |
(1) | ||||||||
new T |
(2) | ||||||||
[編輯] 解釋
預設初始化在三種情況下執行:
1) 當一個具有自動、靜態或執行緒區域性儲存期的變數在沒有初始化器的情況下宣告時;
2) 當一個具有動態儲存期的物件透過沒有初始化器的new 表示式建立時;
3) 當基類或非靜態資料成員未在建構函式初始化列表中提及,並且該建構函式被呼叫時。
預設初始化的效果是:
- 如果
T
是一個(可能是 cv 限定的)非 POD(直到 C++11) 類型別,則考慮建構函式並針對空引數列表進行過載決議。選擇的建構函式(它是預設建構函式之一)被呼叫以提供新物件的初始值; - 如果
T
是陣列型別,則陣列的每個元素都預設初始化; - 否則,不執行任何初始化(參見註釋)。
[編輯] const 物件的預設初始化
如果程式要求預設初始化一個 const
限定型別 T
的物件,則 T
應為const 預設可構造類型別或其陣列。
如果 T
的預設初始化會呼叫 T
的使用者提供建構函式(不是從基類繼承的)(自 C++11 起),或者如果
只有具有自動儲存持續時間的(可能是 cv 限定的)非 POD 類型別(或其陣列)在沒有初始化器的情況下被視為預設初始化。具有動態儲存持續時間的標量和 POD 型別被視為未初始化(自 C++11 起,這種情況被重新歸類為一種預設初始化)。 |
(C++11 前) |
|
(C++11 前) |
(C++11 起) |
T
的每個可能構造的基類都是 const 預設可構造的。
[編輯] 不確定和錯誤的值
當為具有自動或動態儲存持續時間的物件分配儲存空間時,該物件具有一個不確定的值。 如果未對物件執行初始化,則該物件將保留不確定的值,直到該值被替換。 |
(直到 C++26) |
當為具有自動或動態儲存持續時間的物件分配儲存空間時,構成物件儲存的位元組具有以下初始值:
如果未對物件(包括子物件)執行初始化,則此類位元組將保留其初始值,直到該值被替換。
|
(C++26 起) |
如果評估產生不確定的值,則行為是未定義的。
如果評估產生錯誤的值,則行為是錯誤的。 |
(C++26 起) |
[編輯] 特殊情況
以下型別是未初始化友好型:
(C++17 起) |
- unsigned char
- char,如果其底層型別是 unsigned char
給定一個不確定或錯誤(自 C++26 起)的值 value,value 的未初始化結果值是:
- 不確定的值,如果 value 也是不確定的值。
|
(C++26 起) |
如果評估 eval 產生一個未初始化友好型別的不確定或錯誤(自 C++26 起)的值 value,則在以下情況下行為是明確定義的:
- eval 是以下表達式和運算元之一的評估:
- 在這種情況下,操作的結果是 value 的未初始化結果值。
- eval 是簡單賦值運算子的右運算元的評估,其左運算元是未初始化友好型別的左值。
- 在這種情況下,左運算元引用的物件的值被 value 的未初始化結果值替換。
- eval 是初始化表示式的評估,用於初始化未初始化友好型別的物件。
(C++17 起) |
- 在這種情況下,該物件被初始化為 value 的未初始化結果值。
轉換未初始化友好型別的不確定值會產生不確定值。
轉換未初始化友好型別的錯誤值會產生錯誤值,轉換的結果是轉換後的運算元的值。 |
(C++26 起) |
// Case 1: Uninitialized objects with dynamic storage duration // All C++ versions: indeterminate value + undefined behavior int f(bool b) { unsigned char* c = new unsigned char; unsigned char d = *c; // OK, “d” has an indeterminate value int e = d; // undefined behavior return b ? d : 0; // undefined behavior if “b” is true } // Case 2: Uninitialized objects with automatic storage duration // until C++26: indeterminate value + undefined behavior // since C++26: erroneous value + erroneous behavior int g(bool b) { unsigned char c; // “c” has an indeterminate/erroneous value unsigned char d = c; // no undefined/erroneous behavior, // but “d” has an indeterminate/erroneous value assert(c == d); // holds, but both integral promotions have // undefined/erroneous behavior int e = d; // undefined/erroneous behavior return b ? d : 0; // undefined/erroneous behavior if “b” is true } // Same as case 2 void h() { int d1, d2; // “d1” and “d2” have indeterminate/erroneous values int e1 = d1; // undefined/erroneous behavior int e2 = d1; // undefined/erroneous behavior assert(e1 == e2); // holds assert(e1 == d1); // holds, undefined/erroneous behavior assert(e2 == d1); // holds, undefined/erroneous behavior // no undefined/erroneous behavior, // but “d2” has an indeterminate/erroneous value std::memcpy(&d2, &d1, sizeof(int)); assert(e1 == d2); // holds, undefined/erroneous behavior assert(e2 == d2); // holds, undefined/erroneous behavior }
[編輯] 註釋
引用和 const 標量物件不能預設初始化。
功能測試宏 | 值 | 標準 | 特性 |
---|---|---|---|
__cpp_constexpr |
201907L |
(C++20) | constexpr 函式中的平凡預設初始化和 asm 宣告 |
[編輯] 示例
執行此程式碼
#include <string> struct T1 { int mem; }; struct T2 { int mem; T2() {} // “mem” is not in the initializer list }; int n; // static non-class, a two-phase initialization is done: // 1) zero-initialization initializes n to zero // 2) default-initialization does nothing, leaving n being zero int main() { [[maybe_unused]] int n; // non-class, the value is indeterminate std::string s; // class, calls default constructor, the value is "" std::string a[2]; // array, default-initializes the elements, the value is {"", ""} // int& r; // Error: a reference // const int n; // Error: a const non-class // const T1 t1; // Error: const class with implicit default constructor [[maybe_unused]] T1 t1; // class, calls implicit default constructor const T2 t2; // const class, calls the user-provided default constructor // t2.mem is default-initialized }
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
CWG 178 | C++98 | 沒有值初始化; 空初始化器呼叫預設初始化 (儘管 new T() 也執行零初始化) |
空初始化器呼叫 值初始化 |
CWG 253 | C++98 | const 物件的預設初始化不能 呼叫隱式宣告的預設建構函式 |
如果所有子物件都已初始化,則允許 |
CWG 616 | C++98 | 任何未初始化物件的左值到右值轉換總是未定義行為 未定義 |
允許不確定的 unsigned char |
CWG 1787 | C++98 | 從不確定的 unsigned char 讀取 快取到暫存器中是未定義行為 |
已明確定義 |