1.C++中指定初始化值的方式有4種方式: (1)小括號 int x(0); (2)等號 int x = 0; (3)大括號 int x{0}; (4)等號和大括號 int x = {0}; 2.C++11統一初始化, 即使用大括號初始化方式, 其使用場景主要有以下3種: (1)類非靜態成員指定默認值 (2)為容器賦值 vector<int> vec = {1, 2, 3}; (3)對不支持拷貝操作的對象賦值 unique_ptr<int> p{}; 之所以稱為統一初始化, 其原因在於上述3種使用場景中, 第(1)種不支持小括號; 第(2)種不支持等號和小括號; 第(3)種不支持等號. 3.統一初始化的優勢: (1)能禁止內置類型之間的隱式窄化轉換, 即表達式無法保證接收對象能夠表達其值, 則代碼不能通過編譯(至少會給出編譯警告)! 如 double d{}; long x{d}; (2)可以有效解決小括號定義對象卻解析為聲明函數的問題. 如 int x(); 聲明為函數 x 而不是定義變量, 使用統一初始化則不會出現問題. 4.統一初始化的不足: 不足之處在於重載匹配過程變得更加復雜, 難於理解: (1)對重載函數, 統一初始化使用大括號會將數據聲明為 initializer_list 對象, 只有重載匹配過程中, 無法找到 initializer_list類型的形參時, 其它函數才會成為可選函數. 因此, 對聲明了 initializer_list 形參的重載函數, 則使用統一初始化的代碼會優先匹配該函數, 而其他更精確匹配的版本可能沒有機會被匹配. 其中需要特別注意的是經常使用容器 vector. 如 vector<int> vec(10, 2) 和 vector<int> vec{10,2}, 前者是含有 10 個元素的對象, 而后者是只包含 10 和 2 兩個元素的對象. (2)對於構造函數, 空大括號構造一個對象時, 不是匹配 initializer_list 形參的版本, 而是默認構造函數. class Test { public: Test() { PRINT_POS(); } template <typename T> Test(std::initializer_list<T> ls) { Q_UNUSED(ls); PRINT_POS(); } }; 進行如下調用時, Test t1{}; Test t2{1}; // Test t3{{}}; //error: no matching function for call to 'Test::Test(<brace-enclosed initializer list>)' Test t4{{1}}; Test t5({}); 其中 t1 和 t5 使用默認構造函數, t2 和 t4 使用列表初始化構造函數, t3 則不能定義. (3)對於 initializer_list 模板特例化版本, 情形較第2種又有所不同. a. void foo(int); b. template <typename T> void foo(initializer_list<T> lsi); 當進行以下函數調用 foo(0); foo({}); foo({0}); 時, 分別調用的是 a, a, b. c. void foo(int); d. void foo(initializer_list<int> lsi); 當進行以下函數調用 foo(0); foo({}); foo({0}); 時, 分別調用的是 c, d, d.
