名稱空間
變體
操作

值初始化

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
通用主題
流程控制
條件執行語句
if
迭代語句(迴圈)
跳轉語句
函式
函式宣告
Lambda 函式表示式
inline 說明符
動態異常規範 (直到 C++17*)
noexcept 說明符 (C++11)
異常
名稱空間
型別
說明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
儲存期說明符
初始化
 
 

這是當物件以一個空的初始化器構造時所進行的初始化。

目錄

[編輯] 語法

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 起)組成的初始化器建立無名臨時物件時;
2,6) 當透過 new 表示式以一個由空括號或花括號(C++11 起)組成的初始化器建立具有動態儲存期的物件時;
3,7) 當非靜態資料成員或基類使用一個由空括號或花括號(C++11 起)組成的成員初始化器進行初始化時;
4) 當宣告具名物件(自動、靜態或執行緒區域性)時,其初始化器由一對花括號組成。

在所有情況下,若使用空的花括號對 {}T 為聚合型別,則進行聚合初始化,而非值初始化。

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() 擴容時,都會對其元素進行值初始化,除非它們的分配器自定義了 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 類物件的值初始化可能涉及
零初始化,即使預設初始化
實際上並未選擇使用者提供的建構函式
沒有
初始化
在這種情況下

[編輯] 參閱