C++11:一致性初始化、初值列(initializer_list)

一、列表初始化/一致性初始化

  • 設計的目的:
    • 在C++11之前,如何初始化一個變量或對象的概念比較混淆。初始化的場景可以發生在:小括號、大括號或賦值操作符中
    • C++11引入了“列表初始化/一致性初始化”,意思爲:面對任何初始化動作,你可以使用相同語法,就是使用大括號
  • 例如下面的都是正確的:
int units_sold = 0;
int units_sold = { 0 };
int units_sold{ 0 };
int units_sold(0);

int values[]{ 1,2,3 };

std::vector<int> v{ 2,3,5,7,11,13,17 };

std::vector<std::string> cites{
    "Berlin","New York","London"
}

局部基礎數據類型的默認初始化

  • 對於局部變量的定義,如果我們沒有給出初始值,那麼這個變量定義的值是不明確的未知的
  • 如果我們使用{}對普通數據類型的變量進行定義,即使沒有給出初始值,那麼會根據數據類型進行默認初始化
  • 例如:
int i;    //亂值
int j{};  //0

int *p;   //p指向未知地址
int *q{}; //q爲nullptr

禁止窄化

  • “窄化”意爲:精度降低或造成數值變動
    • 對於一般的賦值與初始化,允許窄化的發生
    • 對於大括號的初始化,其不允許窄化的發生,如果有,那麼編譯將不通過。主要的原因是爲了防止數據在轉換中的丟失
  • 例如:
int x1(5.3);   //正確,允許double向int轉變,但是x1爲5
int x2 = 5.3;  //正確,同上
int x3{ 5.3 }; //錯誤,不允許,因爲造成了數據丟失

char c1{ 7 };     //正確,7也屬於char
char c2{ 99999 }; //錯誤,99999不屬於char的範圍,不允許轉換

std::vector<int> v1{ 1,2,3,4,5 }; //正確
std::vector<int> v2{ 1.2,8,1.5 }; //錯誤,其中含有double數據

 

二、std::initializer_list

  • 爲了支持“用戶自定義類型之初值列”概念,C++11提供了class template std::initializer_list<>,用來支持以一些列值進行初始化
  • initializer_list在另一篇文章中已經介紹過,可以參閱:https://blog.csdn.net/qq_41453285/article/details/91895105
  • 本文就不詳細介紹語法了,介紹一些演示案例,語法參閱上面的鏈接

一些演示案例

  • std::initializer_list提供begin()和end()兩個成員。例如:
void print(std::initializer_list<int> vals)
{
    for (auto p = vals.begin(); p != vals.end(); ++p)
        std::cout << *p << std::endl;
}

print({ 12,3,5,4,8 });
  • 在類的構造函數使用std::initializer_list。例如:
class P {
public:
    P(int, int);
    P(std::initializer_list<int>);
};

int main()
{
    P p(77, 5);      //調用給P(int, int)
    P p2(77, 5, 20); //錯誤,

    P p3{ 77,5 };       //調用P(std::initializer_list<int>)
    P p4 = { 77,5 };    //調用P(std::initializer_list<int>)
    P p5{ 77,5,10,15 }; //調用P(std::initializer_list<int>)

    return 0;
}

//備註,如果P沒有提供P(std::initializer_list<int>),那麼上面的p3、p4將
//調用P(int, int),p5初始化將錯誤
  • explicit將抑制類的構造函數轉換行爲。例如:
class P {
public:
    P(int, int);
    explicit P(int, int, int);
};

int main()
{
    P p(77, 5);      //正確,調用P(int, int)
    P p2(77, 5, 20); //正確,調用explicit P(int, int, int)
    P p4 = { 77,5 }; //正確,調用P(int, int)

    //錯誤,explicit關鍵字抑制initializer_list列表使用P(int, int, int)構造函數
    P p4 = { 77,5,10 };
    
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章