C++11的新特性簡單匯總介紹 (二)
1. 范圍for語句
C++11 引入了一種更為簡單的for語句,這種for語句可以很方便的遍歷容器或其他序列的所有元素
vector<int> vec = {1,2,3,4,5,6}; for(int x: vec) { cout<<x<<endl; }
2. 尾置返回類型
要想引入尾置類型,我們還得從復(fù)雜的類型聲明說起。如果我們需要定義一個(gè)含有10個(gè)int元素的數(shù)組,一般是這樣的:
int arr[10] = {0};
如果要定義指向這個(gè)數(shù)組的指針呢:
int (*p_arr)[10] = &arr; //注意:int *p_arr[10] 表示一個(gè)數(shù)組,有10個(gè)元素,元素類型是int*
如果要定義一個(gè)函數(shù),這個(gè)函數(shù)接受一個(gè)char類型的參數(shù),并返回一個(gè)指向10個(gè)int類型數(shù)組的指針呢:
int (*func(char x))[10];
這樣的聲明是不是看的頭都大了,其實(shí)我們可以簡化一點(diǎn),一般情況下我們可以使用別名進(jìn)行簡化,比如:
typedef int ARR[10] ; // 定義一個(gè)類型 ARR這是一個(gè)數(shù)組類型,含有10個(gè)int類型的元素
using ARR = int[10] ; // 同上
再定義如上的函數(shù):
ARR * func(char x) ; // 函數(shù)返回的類型是 ARR* 也就是指向具有10個(gè)int元素?cái)?shù)組的指針
當(dāng)然在C++11中我們可以用之前講到過的另外一個(gè)關(guān)鍵字decltype:
decltype(arr) * func(char x) ; // decltype(arr)表達(dá)式會(huì)獲得arr的類型
最后就輪到我們本節(jié)要說的C++11的另外一個(gè)特性,尾置返回類型,任何函數(shù)都可以使用尾置返回類型,這種形式對于返回類型比較復(fù)雜的函數(shù)最有效,比如上面的函數(shù)可以使用如下方式:
auto func(char x) -> int(*) [10];
這種形式將函數(shù)的返回類型寫在函數(shù)聲明的最后面,并且在函數(shù)形參列表后面加上 -> 符號,然后緊接著是函數(shù)需要返回的類型,由于函數(shù)的返回類型被放在了形參列表之后,所以在函數(shù)名前面使用一個(gè) auto替代。
3. =default 生成默認(rèn)構(gòu)造函數(shù)
在C++的類中,如果我們沒有定義構(gòu)造函數(shù),編譯器會(huì)為我們合成默認(rèn)的無參構(gòu)造函數(shù),如果我們定義了構(gòu)造函數(shù),則編譯器就不生成默認(rèn)構(gòu)造函數(shù)了,但是如果我們定義構(gòu)造函數(shù)同時(shí)也希望編譯器生成默認(rèn)構(gòu)造函數(shù)呢? C++11中可以通過在構(gòu)造函數(shù)的聲明中直接 =default的方式要求編譯器生成構(gòu)造函數(shù)。
class ClassName{ public: ClassName(int x); ClassName()=default; // 顯示要求編譯器生成構(gòu)造函數(shù) };
4. 類對象成員的類內(nèi)初始化
class ClassName { public: int x = 10; //C++11 之前是不允許的 };
5. lambda表達(dá)式與bind函數(shù)
lambda表達(dá)式是一個(gè)可以被調(diào)用的代碼單元,相當(dāng)于一個(gè)內(nèi)聯(lián)函數(shù),有參數(shù)和返回值以及函數(shù)體。但是跟函數(shù)不同的是,lambda表達(dá)式可以定義在函數(shù)的內(nèi)部,一個(gè)完整的lambda表達(dá)式具有如下形式:
[捕獲列表](參數(shù)列表) mutable -> 返回類型 {函數(shù)體}
int x = 10; int y = 20; auto f = [x,&y](int a ,int b){++y;return a+b+x+y;}; cout<<f(1,2)<<endl; //34 cout<<y<<endl; //21
lambda可以省略參數(shù)列表(如果沒有參數(shù)的話),可以省略返回類型,但是不能省略捕獲部分與函數(shù)體部分,即使捕獲列表為空,也要有一個(gè)空的[],lambda有兩種捕獲,一種是值捕獲,一種是引用捕獲。如果是值捕獲那么lambda中獲得的是捕獲的變量的副本,如果是引用捕獲則獲得的是引用,可以在lambda內(nèi)部修改引用的變量的值,如上x是值捕獲,y是引用捕獲,lambda中默認(rèn)是值捕獲,如果變量前面添加&則是引用捕獲,另外lambda中還有兩種形式的引用捕獲,例如[=]表示值捕獲所有可見的變量,而[&]則表示引用捕獲所有可見變量。如果希望值捕獲所有可見變量,但是又有個(gè)別變量采用引用捕獲呢,[=,&x]表示值捕獲所有可見變量,同時(shí)引用捕獲x。而[&,x]則表示引用捕獲所有可見變量,x采用值捕獲的方式。
有關(guān)bind函數(shù),在很多地方我們可以使用函數(shù)替換lambda表達(dá)式,畢竟如果很多地方需要用到同一個(gè)lambda表達(dá)式,而且這個(gè)lambda表達(dá)式比較長的話,將其定義成函數(shù)應(yīng)該是最好的。對于沒有捕獲列表的lambda表達(dá)式我們可以直接使用函數(shù)替代,例如:
void main() { auto f=[](int x,int y){return x+y}; f(); }
我們可以用下面的方式替代:
int f(int x,int y) { return x+y; } void main() { f(); }
與上面的lambda是等價(jià)的,但是對于有捕獲列表的lambda表達(dá)式應(yīng)該怎么處理呢,例如:
void main() { int x = 10; int y = 20; auto f = [x,&y](int a ,int b){return a+b+x+y;}; //一個(gè)值捕獲,一個(gè)引用捕獲 f(33,44); }
如果轉(zhuǎn)換成函數(shù)的形式:
int x = 10; int y = 20; int f(int a,int b) { return a+bx+y; } void main() { f(33,44); }
這是一種可行的方法,但是總不能把所有的捕獲變量定義成全局變量吧?,F(xiàn)在的關(guān)鍵問題是lambda的捕獲表達(dá)式中的內(nèi)容轉(zhuǎn)換成函數(shù)不可行,C++11提供了bind函數(shù)來完成這樣的操作。
#include <functional> //bind() #include <iostream> using namespace std; using namespace std::placeholders; // _1,_2所在的命名空間 int f(int x,int y,int a,int b) { return a+b+x+y; } void main() { int x = 10; int y = 20; auto f_wrap = bind(f,x,y,_1,_2); cout<<f_wrap(33,44)<<endl; // _1,_2是占位符,表示調(diào)用f_wrap的時(shí)候_1是第一個(gè)參數(shù),_2是第二個(gè)參數(shù)。最終會(huì)被替換成調(diào)用 f(10,20,33,44) }
如果引用類型的捕獲怎么做呢,看下面的例子,用lambda是這樣的:
#include <iostream> #include <functional> using namespace std; using namespace std::placeholders; void main() { int x = 10; ostream &o = cout; auto f =[&o](int a){o<<a<<endl;}; // 注意這里的輸出對象是用的引用捕獲 f(x); }
使用bind是這樣的:
#include <iostream> #include <functional> using namespace std; using namespace std::placeholders; void f(ostream &o,int x) { o<<x<<endl; } int main() { int x = 10; auto f_wrap = bind(f,ref(cout),_1); //將變量的引用傳遞到bind中是個(gè)問題,為此C++11提供了ref()函數(shù)用于獲得引用 f_wrap(x); return 0 ; }
6. 智能指針share_ptr,unique_ptr
C++11中引入了幾種智能指針,智能指針能夠自動(dòng)釋放所指向的對象,其中shared_ptr允許多個(gè)指針指向同一個(gè)對象,unique_ptr則獨(dú)占所指向的對象,我們主要說明shared_ptr的使用。通過使用make_shared<type>()函數(shù)產(chǎn)生智能指針對象。
shared_ptr<int> p = make_shared<int>(40); // p指向一個(gè)值為40的int對象
shared_ptr<string> p2 = make_shared<string>(10,'c'); //指向值為'cccccccccc'的string對象
make_shared<type>()函數(shù)中傳遞的值要與對應(yīng)的type的構(gòu)造函數(shù)相匹配,實(shí)際上應(yīng)該就是直接調(diào)用的對應(yīng)type的構(gòu)造函數(shù)。
我們可以使用new初始化的指針來初始化智能指針:
share_ptr<int> p (new int(40));
p.get(); // 使用share_ptr<type>的get()函數(shù)來獲得其關(guān)聯(lián)的原始指針。
shared_ptr對象在離開其作用域(例如一個(gè)函數(shù)體),會(huì)自動(dòng)釋放其關(guān)聯(lián)的指針指向的動(dòng)態(tài)內(nèi)存,就像局部變量那樣。另外多個(gè)shared_ptr可以指向一個(gè)對象,當(dāng)最后一個(gè)shared_ptr對象銷毀的時(shí)候才會(huì)銷毀其關(guān)聯(lián)的那個(gè)對象的動(dòng)態(tài)內(nèi)存。這里使用了引用記數(shù)。
7. 右值引用與move調(diào)用,移動(dòng)構(gòu)造函數(shù)
為了支持移動(dòng)操作,C++11中使用了一種稱為右值引用的類型。移動(dòng)操作是什么呢,一般情況下我們將一個(gè)對象賦值給另一個(gè)對象的時(shí)候會(huì)調(diào)用對象到拷貝構(gòu)造函數(shù)或者拷貝賦值運(yùn)算符。而移動(dòng)構(gòu)造函數(shù)和移動(dòng)賦值運(yùn)算符則用來將數(shù)據(jù)從一個(gè)對象移動(dòng)到另一個(gè)對象。在很多情況下對象拷貝之后需要被銷毀,此時(shí)使用移動(dòng)操作會(huì)大幅提高性能。右值引用被使用之后,其關(guān)聯(lián)的對象會(huì)被銷毀。右值引用使用兩個(gè)&&表示,例如 int && 表示右值引用,而int &則是左值。通過C++11標(biāo)準(zhǔn)庫提供的函數(shù) std::move()可以得到某一對象的右值引用。
TestClass::TestClass(TestClass &&t) noexcept //移動(dòng)構(gòu)造函數(shù)不應(yīng)該拋出任何異常
:x(t.x),y(t.y),z(t.z),p(t.p)
{
t.p=nullptr; // 實(shí)現(xiàn)移動(dòng)操作之后需要保證被移動(dòng)的對象的析構(gòu)是安全的,所以源對象的指針成員置為空,隨后t的析構(gòu)函數(shù)將會(huì)被自動(dòng)調(diào)用,t被銷毀。
}
8. function
C++11中提供了名為function的標(biāo)準(zhǔn)庫類型,定義在頭文件<functional>中,該類型用來存儲(chǔ)一個(gè)可調(diào)用的對象,統(tǒng)一了所有可以像函數(shù)一樣調(diào)用的調(diào)用形式,例如:
#include <functional> #include <iostream> using namespace std; int add(int x,int y) { return x+y; } class Add { public: int operator()(int x,int y) { return x+y; } }; void main() { //function模版的參數(shù)是函數(shù)調(diào)用形式,包括返回類型,以及參數(shù)列表個(gè)數(shù)和類型 function<int(int,int)> f1 = add; //函數(shù)指針 function<int(int,int)> f2 = Add(); // 可調(diào)用類對象 function<int(int,int)> f3 = [](int x,int y){return x+y;}; //lambda表達(dá)式 cout<<f1(10,20)<<" "<<f2(30,40)<<" "<<f3(50,60)<<endl; }
9. 其他新增類型(array,forward_list,bitset,regex)
實(shí)際上C++11中除了一些語法特性新增之外,還增加了一些新的庫。例如array相當(dāng)于我們傳統(tǒng)使用的定長數(shù)組,支持隨機(jī)訪問,不能添加刪除元素,不可以像vector一樣增長,使用array比傳統(tǒng)數(shù)組更加安全。
forward_list是C++11中增加的單向鏈表
regex則是C++11中新增的正則表達(dá)式庫
10. 總結(jié)
C++11中增加了一些庫,庫本身的使用不做過多介紹,可以參考C++標(biāo)準(zhǔn)庫/STL源碼剖析,這都是用單獨(dú)的大部頭書籍講解的,有些特性和庫是我感覺比較驚艷的,例如:
- auto 定義:可以讓編譯器自動(dòng)推算定義的變量類型,而不需要寫長長的一串類型,特別是在含有迭代器的類型上。
- decltype :可以根據(jù)已知的變量來定義一個(gè)跟該變量一樣的類型。
- lambda:個(gè)人認(rèn)為這是C++11中增加的最驚艷的特性之一,對應(yīng)的還有bind()函數(shù),其實(shí)這些內(nèi)容是從Boost中來的。
- 智能指針:shared_ptr 雖然在以前的C++中有類似auto_ptr的智能指針,但是auto_ptr有一些缺陷并不算很好用。
- function類型:標(biāo)準(zhǔn)庫的function類型定義了一種可調(diào)用對象,該類型統(tǒng)一了所有可以當(dāng)作函數(shù)一樣調(diào)用的調(diào)用形式,例如lambda,函數(shù)指針,重載了函數(shù)調(diào)用運(yùn)算符()的類對象等,該特性也是參考了Boost庫。
- regex庫:C++11中總算有了方便的regex可以使用了。
欄 目:C語言
下一篇:C語言 二叉樹的鏈?zhǔn)酱鎯?chǔ)實(shí)例
本文標(biāo)題:C++11的新特性簡單匯總介紹 (二)
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/2167.html
您可能感興趣的文章
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)式函數(shù)庫
- 04-02c語言中對數(shù)函數(shù)的表達(dá)式 c語言中對數(shù)怎么表達(dá)
- 04-02C語言中怎么打出三角函數(shù) c語言中怎么打出三角函數(shù)的值
- 01-10c語言求1+2+...+n的解決方法
- 01-10求子數(shù)組最大和的解決方法詳解
- 01-10深入理解約瑟夫環(huán)的數(shù)學(xué)優(yōu)化方法
- 01-10深入二叉樹兩個(gè)結(jié)點(diǎn)的最低共同父結(jié)點(diǎn)的詳解
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)- 解析最少換車次數(shù)的問題詳解
- 01-10c語言 跳臺階問題的解決方法
- 01-10如何判斷一個(gè)數(shù)是否為2的冪次方?若是,并判斷出來是多少次方


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達(dá)式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10C#中split用法實(shí)例總結(jié)