C++ 列表初始化


C++ 列表初始化

C++11 中,引入了用 {} 執行初始化的統一形式,C++11 稱這種形式為統一初始化(Uniform initialization)

使用這種形式,可以解決所謂的“C++最令人惱怒的解析問題”

最令人惱怒的解析問題

該問題源於函數風格的轉型和函數聲明之間的相似性,導致很多代碼都會被看做是函數聲明

考慮這段代碼

ifstream dataFile("ints.dat");
list<int> data(istream_iterator<int>(dataFile), istream_iterator<int>());

原意是用一對流迭代器去初始化列表,但運行后你會發現,它什么都沒有做

原因在於編譯器會認為 data 是一個函數

  • 第一個參數 dataFile 是 istream_iterator<int> 類型的對象
  • 第二個參數是不接受參數,返回 istream_iterator<int> 對象的函數

因為在函數聲明中

  • 包裹形參名的圓括號會被無視
  • int f(double d);int f(double (d)); 是等價的
    • 參數是 double 類型的 d
  • 空的圓括號會被認為是這里有一個函數類型的參數
    • int g(double ());
    • 參數是返回值為 double,參數為空的函數
class Widget
{
    //假設Widget有默認構造器
};

Widget w();

在這個例子中,w 並不是 Widget 對象,而是返回值為 Widget 類型的函數

C++ 11 前的解決方案

將參數聲明包裹到圓括號里是非法的,但將函數調用的參數包裹在圓括號里是合法的:

list<int> data((istream_iterator<int>(dataFile)), istream_iterator<int>());

一種可讀性更好、更合理的方式:

ifstream dataFile("ints.dat");
istream_iterator<int> begin(dataFile);
istream_iterator<int> end;
list<int> data(begin, end);

列表初始化

用列表初始化來解決上面的問題

list<int> data{ istream_iterator<int>{dataFile}, istream_iterator<int>{} };

Obj(1.0)Obj{1.0} 的一個區別是:前者允許調用 Obj(int),而列表初始化不允許存在精度損失的類型轉換

列表初始化的限制

列表初始化主要的限制是,如果一個類既有使用初始化列表的構造函數,又有不使用初始化列表的構造函數,那編譯器會千方百計地試圖調用使用初始化列表的構造函數,導致各種意外

vector<int> v{3, -1};
for (auto i : v) {
	cout << i << endl;
}

比如上面的代碼,可能本意是構造一個 3 個元素,初始值都是 -1 的 vector,但編譯器會去嘗試調用列表初始化構造函數,構造一個 [3, -1] vector 出來

對此,比較好的做法是:

  • 如果一個類沒有使用初始化列表的構造函數時,初始化該類對象可全部使用統一初始化語法
  • 如果一個類有使用初始化列表的構造函數時,則只應用在初始化列表構造的情況

initializer_list

initializer_list 定義在同名頭文件中

template< class T >  
class initializer_list;

initializer_list 是一種輕量級的代理對象,用來訪問 T 類型的對象數組

  • 可以實現為一對指針,或指針加數組長度
  • initializer_list 對象被拷貝時,底層數組不會被拷貝
  • 底層數組是 const T[N] 類型的臨時數組
    • 每個元素都是從 {} 列表中拷貝來的
    • initializer_list 對象中的元素永遠是常量值,無法被修改
  • 有點像 string_view 或 asio 中的 buffer

在以下幾種情況中, initializer_list 對象會被自動構造

  • {} 列表初始化對象,且該對象的構造函數接受 initializer_list 參數
    • 標准庫容器基本都會接受 initializer_list<value_type> 類型的參數
    • 因此標准庫容器基本都是可以使用列表初始化的
  • {} 列表作為賦值語句的右操作數/函數的參數,對應的賦值運算符/函數接受 initializer_list 參數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM