摘自:深入應用C++11:代碼優化與工程級應用
在C++98/03中存在着種類繁多的初始化方式。C++11爲了統一初始化方式,提出了列表初始化的概念。
#1.3.1 統一的初始化
在C++98/03中,只有普通數組和POD類型可以使用初始化列表。
【POD類型】plain old data類型,即可以直接用memcpy複製的對象。如:
int i_arr[3]={1,2,3};
struct a
{
int x;
int y;
}a={1,2};
在C++11中,初始化列表可以用於任何對象的初始化。
- 對普通數組和POD類型進行初始化。
- 之前使用()調用構造函數,可以使用初始化列表替換。
- 在堆上分配的動態數組,可以使用初始化列表。
- 初始化列表可以直接用在函數返回值上。 如:
struct Foo
{
int x;
int y;
};
int *a=new int{1};
double p=double{p};
int *arr=new int[4]{1,2,3,4};
Foo function()
{
return {1,2};
}
在初始化時,{}前面的=書寫與否不會影響初始化的行爲。
#1.3.2 列表初始化的使用細節
對於一個聚合類型,使用初始化列表相當於對其中的每個元素分別賦值;
對於非聚合類型,需要先定義一個構造函數,使用初始化列表將調用其構造函數。
【聚合類型】的定義:
- 類型是一個普通數組。
- 類型是一個類(class、struct、union)且
- 無用戶自定義的構造函數。
- 無private和protected的非靜態數據成員
- 無基類;
- 無虛函數;
- 不能有直接初始化的非靜態數據成員(GCC中可以)
聚合類型的定義並非遞歸的,當一個類的非靜態成員是非聚合類型時,這個類也可能是聚合類型。如:
struct ST
{
int x;
double y;
private:
int z;
};
struct Foo
{
ST st;
int x;
double y;
};
Foo foo{{},1,2.5};
其中{}可以用來調用無參構造函數。
#1.3.3 初始化列表
##任意長度的初始化列表
爲了讓類的構造函數(或者其他函數)擁有任意長度初始化的能力,C++11在stl中引入了std::initialzer_list這個輕量級的模板。如:
class FooVector
{
public:
FooVector(std::initializer_list<int> list)
{
for(auto i:list)
{
cout<<i<<endl;
}
}
};
FooVector fooVector{1,2,3,4,5};
void Function(std::initializer_list<int> list)
{
for(auto i:vect)
{
cout<<i<<endl;
}
return ;
}
Function({1,2,3,4,5});
##std::initialzer_list的一些細節
- 它是一個輕量級的容器類型,iterator、size()、begin()、end();
- std::initialzer_list可以接受任意長度的初始化列表,但元素類型必須是相同類型T;
- std::initialzer_list的傳遞和賦值的效率高,它內部只存儲了列表中元素的引用(不需要進行值拷貝);這是它與std:vector的重要區別;
- 因爲std::initialzer_list的元素可能是保存在函數棧中的局部變量,因此std::initialzer_list不適合做函數的返回值;而應使用std::vector。
- std::initialzer_list只能被整體初始化或賦值。
std::initializer_list<int> func1()
{
int a=1,b=2;
return {a,b};//a、b在返回時沒有被拷貝,錯誤的寫法
}
std::vector<int> func2()
{
int a=1,b=2;
return {a,b};
}
#1.3.4 防止類型收窄
【類型收窄】導致數據內容發送變化或者精度丟失的隱式類型轉換。如:
- 浮點數隱式轉換爲整型數;
- 高精度浮點數隱式轉換爲低精度浮點數;
- 整型數轉換爲浮點數,且超出了浮點數的表示範圍;
- 長整型數轉換爲短整型數
在C++98/03中,編譯器對於類型收窄不會報錯;
在C++11中,列表初始化檢查類型收窄的情況,並報警告或錯誤。如:
int a=1.1; //OK
int b={1.1}; //ERROR
const int x=1024;
const int y=1;
char c={x}; //ERROR
char d={y}; //OK
float ff=1.2;
float fd={1.2};
在fd的初始化沒有引起類型收窄,但是VS2013中會報錯,而gcc4.8中不會報錯。