天天看點

Google C++每周貼士 #172: 指派初始化器每周貼士 #172: 指派初始化器

(原文連結:https://abseil.io/tips/172 譯者:[email protected])

每周貼士 #172: 指派初始化器

  • 最初釋出于:2019-12-11
  • 作者:Aaron Jacobs
  • 更新于:2020-04-06
  • 短連結:abseil.io/tips/172

指派初始化器是C++20中的一種文法,以緊湊、易讀、易維護的方式初始化結構體内容。為了取代繁複的

struct Point {
  double x;
  double y;
  double z;
};

Point point;
point.x = 3.0;
point.y = 4.0;
point.z = 5.0;
           

可以用指派初始化器寫成

Point point = {
    .x = 3.0,
    .y = 4.0,
    .z = 5.0,
};
           

這樣稍稍減少了重複,但更重要的是,可以在更多上下文下被使用。例如,它意味着結構體可以是

const

,而不必依靠笨拙的變通方法:

// 清晰地向(可能更大更複雜的代碼的)讀者表明,該結構體永遠不會改變。
const Point character_position = { .x = 3.0 };
           

或者可以被直接用在函數調用端,而不必在對應作用域中引入額外的辨別符:

std::vector<Point> points;
[...]
points.push_back(Point{.x = 3.0, .y = 3.0});
points.push_back(Point{.x = 4.0, .y = 4.0});
           

文法

指派初始化器是聚合初始化的一種形式,是以隻能與聚合在一起使用。這基本意味着“沒有使用者提供的構造函數或虛函數的結構體或類”,也就基本意味着Google風格中使用

struct

(而不是

class

)的場景。

C++20的指派初始化器的文法,跟你對其他C++特性(如構造函數成員初始化清單)的期待是一緻的。顯式提及的字段以表達式提供的順序被初始化,而且允許忽略那些你希望有“預設”行為的字段:

Point point = {
    .x = 1.0,
    // y會是0.0
    .z = 2.0,
};
           

上面的“預設”是什麼意思?除特殊情況(如

union

)以外的回答是:

  • 如果結構體定義包括了預設成員初始化器(也就是字段定義長得像

    std::string foo = "default value";

    ),那它就被使用。
  • 否則這個字段就以

    = {}

    初始化。實踐中,這意味着平坦資料類型(plain old data types)拿到零值,而更複雜的類拿到預設構造的執行個體。

這通常是最不吓人的行為。詳情請參考标準。

一些曆史和語言瑣事

指派初始化器從C99開始就是C語言标準的一部分,且在此之前就被編譯器以非标準擴充提供使用。但直到最近它都不是C++的一部分:碩果僅存的C不是C++子集的例證之一。因為這個原因,Google風格指南曾經說不要用它。

經過了兩個十年,情況總算改變了:指派初始化器現在是C++20标準的一部分了。

相比于C版本,C++20形式的指派初始化器有一些限制:

  • C++20要求指派器中字段的順序與它們在結構體定義中保持一緻(是以

    Point{.y = 1.0, .x = 2.0}

    不合法)。C不要求這點。
  • C允許混搭指派的和非指派的初始化器(

    Point{1.0, .z = 2.0}

    ),但C++20不允許。
  • C支援一種文法來稀疏地初始化數組,被稱為“數組指派器”。這貨不是C++20的一部分。

繼續閱讀