C++統一初始化


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 個元素的對象, 而后者是只包含 102 兩個元素的對象.
(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.

 


免責聲明!

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



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