命名空間
變體
動作

值初始化

出自 cppreference.com
< cpp‎ | language
 
 
C++ 語言
一般主題
流程控制
條件執行陳述式
if
疊代陳述式 (迴圈)
for
範圍 for (C++11)
跳躍陳述式
函式
函式宣告
Lambda 函式運算式
inline 指定符
動態例外規範 (直到 C++17*)
noexcept 指定符 (C++11)
例外
命名空間
型別
指定符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
儲存期指定符
初始化
 
 

這是當物件以空初始化器(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 起)組成時;
2,6) 當透過 new 表達式創建具有動態儲存期的物件,且其初始化器由一對空圓括號或花括號(C++11 起)組成時;
3,7) 當非靜態資料成員或基底類別使用成員初始化器,且初始化器為一對空圓括號或花括號(C++11 起)時;
4) 當具名物件(自動、靜態或執行緒局部)宣告時,其初始化器由一對花括號組成時。

在所有情況下,如果使用空的圓括號對 {}T 是聚合型別(aggregate type),則會執行聚合初始化而非值初始化。

如果 T 是沒有預設建構函式但擁有接受 std::initializer_list 之建構函式的類別型別,則執行列表初始化

(C++11 起)

值初始化的效果如下:

  • T 為(可能含有 cv 限定符的)類別型別:
  • 否則,若 T 是陣列型別,則陣列的每個元素都會進行值初始化。
  • 否則,該物件會進行零初始化。

[編輯] 附註

語法 T object(); 並不會初始化物件;它宣告了一個不帶參數且回傳 T 的函式。在 C++11 之前,對具名變數進行值初始化的方式是 T object = T();,這會值初始化一個臨時物件,然後拷貝初始化該變數:大多數編譯器在此情況下會省略拷貝

參考不能進行值初始化。

函式風格轉型所述,若 T 為陣列型別,語法 T() (1) 是禁止的,而 T{} (5) 則是允許的。

所有標準容器(std::vectorstd::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 類別物件的值初始化可能涉及
零初始化,即使預設初始化
並沒有實際選擇使用者提供的建構函式
不存在
零初始化之後
在此情況下

[編輯] 參見

English Deutsch 日本語 中文(简体) 中文(繁體)