柚子快報(bào)激活碼778899分享:開發(fā)語言 C++——C++11
柚子快報(bào)激活碼778899分享:開發(fā)語言 C++——C++11
前言:本篇文章將分享一些C++11版本所產(chǎn)生的一些新的技術(shù)以及對老版本的優(yōu)化。
目錄
一.C++11簡介
二.統(tǒng)一的列表初始化
1.{}初始化
2.std::initializer_list
三.右值引用和移動語義
1.左值引用和右值引用
?2.兩者的比較
(1)左值引用
?(2)右值引用
3.移動語義
4.萬能引用
四.lambda表達(dá)式
1.基礎(chǔ)使用
2.捕捉列表
五.可變模板參數(shù)
六.function包裝器 ???????
一.C++11簡介
C++11是C++委員會自C++03起,經(jīng)歷了近10年的時(shí)間所進(jìn)行的又一次更新。相比于C++98/03,C++11帶來了數(shù)量可觀的變化,其中包含了約140個(gè)新特性,以及對C++03標(biāo)準(zhǔn)中約600個(gè)缺陷的修正,這使得C++11更像是從C++98/03中孕育出的一種新語言。
相比較而言,C++11能更好地用于系統(tǒng)開發(fā)和庫開發(fā)、語法更加泛華和簡單化、更加穩(wěn)定和安全,不僅功能更強(qiáng)大,而且能提升程序員的開發(fā)效率,公司實(shí)際項(xiàng)目開發(fā)中也用得比較多,所以我們要作為一個(gè)重點(diǎn)去學(xué)習(xí)。
本文主要分享一些實(shí)際中比較實(shí)用的語法。
二.統(tǒng)一的列表初始化
1.{}初始化
在C++98中,標(biāo)準(zhǔn)允許使用花括號{}對數(shù)組或者結(jié)構(gòu)體元素進(jìn)行統(tǒng)一的列表初始值設(shè)定。比如:
struct Point
{
?int _x;
?int _y;
};
int main()
{
?Point p = { 1, 2 };
?return 0;
}
?C++11擴(kuò)大了用花括號括起的列表(初始化列表)的使用范圍,使其可用于所有的內(nèi)置類型和用戶自定義的類型,使用初始化列表時(shí),可添加等號(=),也可不添加:
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 1, 1); // old style
// C++11支持的列表初始化,這里會調(diào)用構(gòu)造函數(shù)初始化
Date d2{ 2022, 1, 2 };
Date d3 = { 2022, 1, 3 };
return 0;
}
2.std::initializer_list
std::initializer_list一般是作為構(gòu)造函數(shù)的參數(shù),C++11對STL中的不少容器就增加std::initializer_list作為參數(shù)的構(gòu)造函數(shù),這樣初始化容器對象就更方便了。也可以作為operator=的參數(shù),這樣就可以用大括號賦值:
vector(initializer_list
{
resize(l.size());
for (auto& e : l)
? ?{
push_back(e);
}
}
?initializer_list包含兩個(gè)指針,一個(gè)指向常量數(shù)組的開始,一個(gè)指向常量數(shù)組的結(jié)尾的下一個(gè)位置。
構(gòu)造函數(shù)的本質(zhì)就是遍歷l,將其數(shù)據(jù)一個(gè)一個(gè)尾插進(jìn)容器。
int main()
{
vector
// 這里{"sort", "排序"}會先初始化構(gòu)造一個(gè)pair對象
map
// 使用大括號對容器賦值
v = {10, 20, 30};
return 0;
}
三.右值引用和移動語義
1.左值引用和右值引用
左值是一個(gè)表示數(shù)據(jù)的表達(dá)式(如變量名或解引用的指針),我們可以獲取它的地址+可以對它賦值,左值可以出現(xiàn)賦值符號的左邊,也可以出現(xiàn)在賦值符號的右邊。定義時(shí)const修飾符后的左值,不能給他賦值,但是可以取它的地址。左值引用就是給左值的引用,給左值取別名。
// 以下的p、b、c都是左值 int* p = new int(0); int b = 1; const int c = 2;
?右值也是一個(gè)表示數(shù)據(jù)的表達(dá)式,如:字面常量、表達(dá)式返回值,函數(shù)返回值(這個(gè)不能是左值引用返回)等等,右值可以出現(xiàn)在賦值符號的右邊,但是不能出現(xiàn)出現(xiàn)在賦值符號的左邊,右值不能取地址。右值引用就是對右值的引用,給右值取別名。
// 以下幾個(gè)都是常見的右值 10; x + y; fmin(x, y);
對左值引用,我們使用單&符號:
// 以下幾個(gè)是對上面左值的左值引用 int*& rp = p; int& rb = b; const int& rc = c; int& pvalue = *p;??
而對右值引用,我們則需使用雙&&符號:?
// 以下幾個(gè)都是對右值的右值引用 int&& rr1 = 10; double&& rr2 = x + y; double&& rr3 = fmin(x, y);?
?2.兩者的比較
(1)左值引用
左值引用只能引用左值,不能引用右值。但是const左值引用既可引用左值,也可引用右值。左值引用是給原值另起一個(gè)別名,兩者共用一個(gè)地址。?
int main() { ????// 左值引用只能引用左值,不能引用右值。 ????int a = 10; ????int& ra1 = a; ??// ra為a的別名 ????//int& ra2 = 10; ??// 編譯失敗,因?yàn)?0是右值 ????// const左值引用既可引用左值,也可引用右值。 ????const int& ra3 = 10; ????const int& ra4 = a; ????return 0; }?
?(2)右值引用
右值引用只能右值,不能引用左值。但是右值引用可以move以后的左值。右值引用本身是左值。右值引用是直接搶奪資源。
int main() { ?// 右值引用只能右值,不能引用左值。 ?int&& r1 = 10;
?// error : “初始化”: 無法從“int”轉(zhuǎn)換為“int &&” ?// message : 無法將左值綁定到右值引用 ?int a = 10; ?int&& r2 = a;
?// 右值引用可以引用move以后的左值 ?int&& r3 = std::move(a);//(move后邊會分享) ?return 0; }
如上例,?r3右值引用a之后,r3得到a的數(shù)據(jù)和地址,而a本身則不再具有資源和地址。
3.移動語義
在我們之前所分享的各種容器中,都擁有構(gòu)造函數(shù)和賦值函數(shù),在C++11之前,這兩個(gè)函數(shù)都是通過左值引用來作為參數(shù),但是C++11之后,我們可以用右值引用作為參數(shù),而兩種函數(shù)名也變?yōu)橐苿訕?gòu)造和移動賦值:
// 移動構(gòu)造
string(string&& s)
:_str(nullptr)
,_size(0)
,_capacity(0)
{
cout << "string(string&& s) -- 移動語義" << endl;
swap(s);
}
// 移動賦值
string& operator=(string&& s)
{
cout << "string& operator=(string&& s) -- 移動語義" << endl; swap(s);
return *this;
}
移動構(gòu)造和移動賦值,相較于傳統(tǒng)的構(gòu)造函數(shù)和賦值函數(shù),因?yàn)橛抑狄每梢灾苯訆Z舍資源,所以就避免了需要創(chuàng)建一個(gè)新的對象來進(jìn)行資源交換這些繁瑣的過程,大大提高了效率。?
4.萬能引用
template
void fun(T&& t)
{}
函數(shù)模版里的右值引用,稱為萬能引用,可以傳左值,右值,const左值及const右值,均會自動識別。
但是這里存在一個(gè)問題,因?yàn)橛抑狄帽旧碓傧乱淮蝹鬟f時(shí)會被識別為左值,所以我們需要添加?xùn)|西來保持右值的本身屬性,而執(zhí)行該步驟的是完美轉(zhuǎn)發(fā):
?std::forward
完美轉(zhuǎn)發(fā)可以保證在傳參過程中參數(shù)會保持其原生類型屬性。
四.lambda表達(dá)式
1.基礎(chǔ)使用
在C++11到來之前,我們想對一個(gè)數(shù)據(jù)集合進(jìn)行排序,可以通過使用sort函數(shù),而遇到自定義類型的數(shù)據(jù)時(shí),如果想要進(jìn)行排序,我們分享過使用仿函數(shù)來進(jìn)行排序。
但是仿函數(shù)的寫法未免有些復(fù)雜和繁瑣,所以C++11中就增加了對自定義類型的數(shù)據(jù)進(jìn)行排序的lambda表達(dá)式,其本質(zhì)為匿名函數(shù)對象。
其結(jié)構(gòu)為:
[捕捉列表] (參數(shù)) mutable?-> 返回值類型?{ 函數(shù)體?}
默認(rèn)情況下lambda表達(dá)式具有常性,如果要取消其常性,則需添加上述表達(dá)式的mutable。
當(dāng)我們僅使用該表達(dá)式可以省略捕捉列表和返回值類型。該表達(dá)式的返回值,可以使用auto類型的數(shù)據(jù)進(jìn)行接收:
auto fun1 = [](int a,int b)->{return a > b;};
auto fun1 = [](int a,int b){return a > b;};
上述表達(dá)式中的->也是可以省略的。
2.捕捉列表
int a = 1,b = 2;
auto swap = [a,b]()
{}
捕捉常量可以使lambda表達(dá)式捕捉到a,b的一份拷貝,但是默認(rèn)為const類型,無法對其進(jìn)行交換,如果需要,則需添加multable取消其常性。
但是就算添加了multable可以進(jìn)行交換,但依然只是交換了拷貝,并不影響a,b本身。如果想要交換a,b本身,就需要傳引用:
int a = 1,b = 2;
auto swap = [&a,&b]()
{}
此種捕捉方式,只能是我們傳什么,就捕捉什么。除此之外,我們還可以一次性捕捉父作用域中的全部對象:
?int a = 1,b = 2,c = 3,d = 4, e = 5;
auto swap = [=]()
{}
傳“=”可以一次性捕捉所有對象,而傳“&”則是一次性捕捉所有引用:?
?int a = 1,b = 2,c = 3,d = 4, e = 5;
auto swap = [&]()
{}
另外,我們還可以混合捕捉:
?int a = 1,b = 2,c = 3,d = 4, e = 5;
auto swap = [&a,&b,c,e]()
{}
五.可變模板參數(shù)
前邊我們分享過什么是可變參數(shù),即函數(shù)的參數(shù)數(shù)量并不固定,可以隨心所欲的添加參數(shù),例如最常用的scanf和printf兩個(gè)函數(shù)。在C++11中,大佬們?yōu)槟0嬉苍O(shè)計(jì)了可變參數(shù),具體結(jié)構(gòu)如下:
// Args是一個(gè)模板參數(shù)包,args是一個(gè)函數(shù)形參參數(shù)包 // 聲明一個(gè)參數(shù)包Args...args,這個(gè)參數(shù)包中可以包含0到任意個(gè)模板參數(shù)。 template
上面的參數(shù)args前面有省略號,所以它就是一個(gè)可變模版參數(shù),我們把帶省略號的參數(shù)稱為“參數(shù)包”,它里面包含了0到N(N>=0)個(gè)模版參數(shù)。?
六.function包裝器
包裝器function是一種類模板,使用包裝器需要添加頭文件include
function<返回值類型(參數(shù)類型...)> 包裝器名字
包裝器可以使用的場景針對于可調(diào)用對象,包括函數(shù)指針,函數(shù)對象,lambda表達(dá)式,以及類的成員函數(shù)。
所謂包裝器,就是給上述舉例的這些包裝一個(gè)相同的外殼,使它們調(diào)用起來更加方便統(tǒng)一:
#include
int f(int a, int b)
{
return a + b;
}
struct Functor
{
public:
int operator() (int a, int b)
{
return a + b;
}
};
class Plus
{
public:
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return a + b;
}
};
int main()
{
// 函數(shù)名(函數(shù)指針)
std::function
cout << func1(1, 2) << endl;
// 函數(shù)對象
std::function
cout << func2(1, 2) << endl;
// lamber表達(dá)式
std::function
{return a + b; };
cout << func3(1, 2) << endl;
// 類的成員函數(shù)
std::function
cout << func4(1, 2) << endl;
std::function
cout << func5(Plus(), 1.1, 2.2) << endl;
return 0;
}
結(jié)語
關(guān)于C++11就分享這么多,喜歡本篇文章記得一鍵三連,我們下期再見!
柚子快報(bào)激活碼778899分享:開發(fā)語言 C++——C++11
文章來源
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。