一.列表初始化
1.在c++98/03中,只有普通陣列和pod型別(plain old data型別,可以直接使用memcpy複製的物件)可以用初始化列表來進行初始化。
int i_arr[3] = ;
long l_arr[3] = ;
struct a
a = ;
2.在c++11中,初始化列表可以用於任何型別物件的初始化列表,它統一了各種物件的初始化方法,使得我們書寫更加簡單清晰。格式:變數名+初始化列表(相比之前少了「=」)。
class foo
private:
foo(const foo &);
};int main();
foo a4 ;
int a5 = ;
int a6 ;
return 0;
}
a3雖然使用了等號,但它仍然是初始化列表。
a3,a4使用了新的初始化方式來初始化物件。
a5,a6是基本資料型別的列表寢始化方法。
a4,a6的寫法在c++98/03中不存在,在c++11中,可以直接在變數名後跟上始初化列表來進行物件的初始化。
1).初始化時,{}前面的等於號是否書寫對初始化行為沒有影響。
int a = ;
int b ;
2). new操作符等可以用圓括號進行初始化的地方,也可以使用初始化列表。
int* a = new int ( 123 );
int* b = new int ;
3).堆上分配的動態陣列也可以使用初始化 列表來進行初始化。
int* arr = new int[3] ;
4).列表初始化還可以作用在函式的返回值上。
struct foo
};foo fun();
}
這裡的return語句如同返回乙個foo(123,321.0)。
二.列表初始化的使用細節
1.
struct a
a = ;
struct b
} b = ; = 0, b.y = 0
a的初始化過程是c++98/03中就有的聚合型別的初始化。它將以拷貝的形式,用初始化列表的值來初始化struct a中的成員。
b由於定義了乙個自定義的建構函式,因此,是以b的建構函式進行初始化的。
什麼情況下,c++會認為它是乙個集合體?
1).型別是乙個普通陣列。
int x = ;
2).型別是乙個類,且
1)).無使用者自定義的建構函式。
struct foo
};foo foo //error
2)).無私有或保護的非靜態資料成員。
struct st
;st s //error
3)).無基類。
struct st
};st s ;
4)).無虛函式。
struct base {};
struct foo : public base
;foo foo ;
5)).不能有{}和=直接初始化的非靜態資料成員。
struct st
;st s ; //error
c++98/03中不能在宣告時進行初始化工作。但是在c++11放寬了這限制。但對乙個類來說,如果對非靜態資料成員進行了初始化,那麼它就不再是乙個聚合型別,就i 能使用初始化列表。
總之,對於聚合型別,使用初始化列對於非聚合型別,使用初始化列表相當於對其中的每個元素分別賦值,而對於非聚合型別,想要使用初始化列表的方法就是定義乙個建構函式。
struct st
private:
int z;
public:
st(int i, double j, int k) : x(i), y(j), z(k) {}
};st s ;
2.
struct foo
;foo foo ;
int arr ;
std::mapmn = , };
std::setss = ;
std::vectorarr = ;
迄今為止,我們所討論的都是按步就班的按照建構函式指定的引數列表進行初化,而像陣列,std::map,std::set,std::vector可以在初始化時,使用任意長度的初始化列表。
實際上,stl中的容器是通過使用std::initializer_list這個輕量級的類模板來完成上述功能的支援。我們只需要在foo新增乙個std::initiallzer_list建構函式,它也將有這種任意長度的初始化能力。
class foo
};foo foo = ; //ok
class foovector
}};class foomap
}};foovector foo_1 = ;
foomap foo_2 = , , };
3.
初始化列表(std::initializer_list)的一些特點:
1).它是乙個輕量級的容器型別,內部定義了iterator等容器必需的概念。
2).對於std::initializer_list而言,它可以接收任意長度的初始化列表,但要求元素必須是同種型別t(或可轉化為t)。
3).它有3個成員介面:size(),begin(),end()。
4).它只能被整體初始化或賦值。
5).std::initializer_list擁有乙個無引數的建構函式,因此,可以直接定義例項,得到乙個空的std::initializer_list。
6).對std::initializer_list的訪問只能通過begin()和end()進行迴圈遍歷,遍歷時取得的迭代器是唯讀的。要修改,只能通過列表初始化表的賦值對std::initializer_list做整體修改。
std::initializer_listlist;
size_t n = list.size(); // n== 0
list = ;
n = list.size(); //n == 5
list = ;;
n = list.size(); // n == 4
7).std::initializer_list在傳遞或賦值的時候跟vector容器不一樣,vector把每個元素都複製一遍,std::initializer_list則是非常高效的,它的內部並不負責儲存初始化列表中元素的拷貝,僅僅儲存了列表中元素的引用而已。
std::initializer_listfund(); //error a,b在返回時並沒有被拷貝
}
三.防止型別收窄
型別收窄包括以下幾種情況:
1).從乙個浮點數隱式轉換為乙個整型數。
2).從高精度浮點數隱式轉換為低精度浮點數。
3).從乙個整型數隱式轉換為乙個長度較短的整型數,並且超出了長度較短的整型數的表示範圍。
4).從乙個整型數隱式轉換為乙個浮點數,,並且超出了浮點數的表示範圍。
上述情況,編譯器並不會報錯,而是給出一些警告。
使用列表初始化來檢查及防止型別收窄。
int a =1.1 //ok
int b = ; //error
float fa = 1e40; //ok
float fb = ; //error
float fc = (unsigned long long)-1; //ok
float fd = ; //ok
float fe = (unsigned long long)1; //ok
float ff = ; //ok
const int x = 1024, y = 1;
char c = x; //ok
char d ; //error
char e = y; //ok
char f = ; //ok
唯一要注意的是,x,y被定義為const int,如果去掉const限定符,那麼最後乙個變數f也會因為型別收窄而報錯。 C 11之列表初始化
c 98使用 對陣列初始化 int arr int arr 4 但對於自定義型別會報錯 vectorv 內建型別 int x1 int x2 int x3 1 2 int x4 int x5 陣列 int arr1 5 int arr2 動態陣列 c 98不支援 int arr3 new int 5...
C 11 就地初始化與列表初始化
在 c 11 之前,只能對結構體或類的靜態常量成員進行就地初始化,其他的不行。class c class c or int b c 11 only int c 7 error 注意,小括號初始化方式不能用於就地初始化。c 11 支援了就地初始化非靜態資料成員的同時,初始化列表的方式也被保留下來,也就...
c 11 就地初始化與列表初始化
還可以看看 在c 11之前,只能對結構體或類的靜態常量成員進行就地初始化,其他的不行。class c class c 或int b c 11 only int c 7 error 1.2就地初始化與初始化列表的先後順序 c 11標準支援了就地初始化非靜態資料成員的同時,初始化列表的方式也被保留下來,...