一、內(nèi)聯(lián)函數(shù)
?普通的函數(shù)在調(diào)用的時(shí)候會(huì)開(kāi)辟函數(shù)棧幀,會(huì)產(chǎn)生一定量的消耗,在C語(yǔ)言中可以用宏函數(shù)來(lái)解決這個(gè)問(wèn)題,但是宏存在以下缺陷:復(fù)雜、容易出錯(cuò)、可讀性差、不能調(diào)試。為此,C++中引入了內(nèi)聯(lián)函數(shù)這種方法。
1.1 定義
?以inline
修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會(huì)在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開(kāi),沒(méi)有函數(shù)調(diào)用建立棧幀的開(kāi)銷(xiāo),所以?xún)?nèi)聯(lián)函數(shù)可以提高程序的運(yùn)行效率。
??普通函數(shù):
int Add(int x, int y)//這里的Add是一個(gè)普通函數(shù)
{
return x + y ;
}
int main()
{
int ret = 0;
ret = Add(3, 5);
cout << ret << endl;
return 0;
}
??內(nèi)聯(lián)函數(shù):
inline int Add(int x, int y)
{
return x + y ;
}
int main()
{
int ret = 0;
ret = Add(3, 5);
cout << ret << endl;
return 0;
}
注意:在默認(rèn)的Debug模式下,內(nèi)聯(lián)函數(shù)是不會(huì)展開(kāi)的,需要進(jìn)行設(shè)置,設(shè)置過(guò)程如下:
1.2 特性
- inline是一種以時(shí)間換空間的做法,如果編譯器將函數(shù)當(dāng)成內(nèi)聯(lián)函數(shù)處理,在編譯階段,會(huì)用函數(shù)體替換函數(shù)調(diào)用。缺陷:可能會(huì)使目標(biāo)文件變大,優(yōu)點(diǎn):少了調(diào)用開(kāi)銷(xiāo),提高程序運(yùn)行效率。
- inline對(duì)編譯器而言只是建議,不同的編譯器關(guān)于inline的實(shí)現(xiàn)機(jī)制可能不同,一般建議:將函數(shù)規(guī)模小的(即函數(shù)不是很長(zhǎng),具體沒(méi)有準(zhǔn)確的說(shuō)法,取決于編譯器內(nèi)部實(shí)現(xiàn))、不是遞歸、且頻繁調(diào)用的函數(shù)采用inline修飾,否則編譯器會(huì)忽略inline特性。
- inline建議函數(shù)聲明和定義不能分離,因?yàn)閮?nèi)聯(lián)函數(shù)在預(yù)處理階段就直接展開(kāi),因此內(nèi)聯(lián)函數(shù)不會(huì)進(jìn)符號(hào)表,因此如果聲明和定義分離,頭文件只有聲明,在預(yù)處理階段,頭文件展開(kāi),只知道該函數(shù)是一個(gè)內(nèi)聯(lián)函數(shù),沒(méi)有對(duì)應(yīng)函數(shù)的定義,因此就無(wú)法完成替換,那就只能等通過(guò)call在鏈接階段去找該函數(shù),但是它是內(nèi)聯(lián)函數(shù),沒(méi)有進(jìn)符號(hào)表,所以鏈接階段就會(huì)報(bào)錯(cuò)。
??為什么是函數(shù)規(guī)模???
?假設(shè)一個(gè)函數(shù)經(jīng)過(guò)編譯,得到五十條匯編指令。普通情況下,調(diào)用此函數(shù)只需要一條call指令,調(diào)用10000此也就10000條call指令,但是如果把這個(gè)函數(shù)設(shè)置成內(nèi)聯(lián)函數(shù),指令的數(shù)量就會(huì)大大增加,因?yàn)閮?nèi)聯(lián)函數(shù)完成的是替換,把所有調(diào)用它的地方,都用函數(shù)體去替換,這也就意味著,原來(lái)1條call指令就能完成的任務(wù),現(xiàn)在替換后就變成了50條指令,假如還是調(diào)用了10000次該函數(shù),那就從10000條call指令,變成了500000條指令,其實(shí)這就是代碼膨脹。
inline int Add(int x, int y)
{
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
cout << "xxxxxxxxxxxx" << endl;
return x + y ;
}
int main()
{
int ret = 0;
ret = Add(3, 5);
cout << ret << endl;
return 0;
}
?對(duì)于上面函數(shù)體比較長(zhǎng)的函數(shù),即使我們?nèi)藶橐?guī)定了它是內(nèi)聯(lián),但最終還是通過(guò)call指令去調(diào)用函數(shù)。
??為什么是被頻繁調(diào)用?
?因?yàn)槠胀ê瘮?shù)在調(diào)用的時(shí)候會(huì)創(chuàng)建函數(shù)棧幀,若頻繁調(diào)用就會(huì)頻繁的創(chuàng)建棧幀,增加消耗。宏和內(nèi)聯(lián),就是為了解決開(kāi)銷(xiāo)問(wèn)題。如果調(diào)用的次數(shù)不多,開(kāi)辟一點(diǎn)棧幀是無(wú)所謂的。
二、auto關(guān)鍵字
2.1 簡(jiǎn)介
?C++11中規(guī)定:auto不再是一個(gè)存儲(chǔ)類(lèi)型指示符,而是作為一個(gè)新的類(lèi)型指示符來(lái)指示編譯器,auto聲明的變量必須由編譯器在編譯時(shí)期推導(dǎo)而得。簡(jiǎn)單來(lái)說(shuō),auto會(huì)根據(jù)表達(dá)式自動(dòng)推導(dǎo)類(lèi)型。
int main()
{
int a = 0;
auto b = a;//自動(dòng)推導(dǎo)出b的類(lèi)型是int
auto c = 1.11 + 1;//自動(dòng)推導(dǎo)出c的類(lèi)型是double
cout << typeid(b).name() << endl;//typeid可用來(lái)查看變量類(lèi)型
cout << typeid(c).name() << endl;
return 0;
}
??注意:
?使用auto定義變量時(shí)必須對(duì)其進(jìn)行初始化,在編譯階段編譯器需要根據(jù)初始化表達(dá)式,來(lái)推導(dǎo)auto的實(shí)際類(lèi)型。因此,auto并非是一種“類(lèi)型”的聲明,而是一個(gè)類(lèi)型聲明的“占位符”,編譯器在編譯階段會(huì)將auto替換為變量實(shí)際的類(lèi)型。
int main()
{
auto a;//錯(cuò)誤,必須要初始化
return 0;
}
2.2 auto使用細(xì)則
??auto與指針和引用結(jié)合起來(lái)使用
?用auto聲明指針類(lèi)型時(shí),用auto和aauto*沒(méi)有任何區(qū)別,但是auto聲明引用類(lèi)型時(shí),必須要加&,如下,如果c不加&的話,就是x的一份拷貝。
int main()
{
int x = 10;
auto a = &x;//根據(jù)右邊推出,a是一個(gè)指針類(lèi)型
auto* b = &x;//右邊必須是一個(gè)地址,因?yàn)榍懊婕恿?
auto& c = x;//引用必須要加&
}
??在同一行定義多個(gè)變量
?當(dāng)在同一行聲明多個(gè)變量的時(shí)候,這些變量必須是相同的類(lèi)型,否則編譯器會(huì)報(bào)錯(cuò),因?yàn)榫幾g器實(shí)際只對(duì)第一個(gè)類(lèi)型進(jìn)行推導(dǎo),然后用推導(dǎo)出來(lái)的類(lèi)型定義其他變量。
int main()
{
auto a = 10, b = 30;
auto c = 60, d = 1.1;//該行編譯失敗,c和d的初始化類(lèi)型不同
}
2.3 不能使用auto的場(chǎng)景
- auto不能作為函數(shù)的參數(shù)
//錯(cuò)誤,編譯器無(wú)法對(duì)x的實(shí)際類(lèi)型進(jìn)行推導(dǎo)
void Text(auto x)
{}
- ·auto不能直接用來(lái)聲明數(shù)組
void Text()
{
//auto arr[] = { 1, 2, 3 };//錯(cuò)誤寫(xiě)法,請(qǐng)勿模仿
int arr[] = {1, 2, 3}//這才是正確寫(xiě)法
}
小Tips:auto在實(shí)際中常被用在:基于范圍的for循環(huán)中、還有l(wèi)ambda表達(dá)式中、其次就是一些非常非常長(zhǎng)的類(lèi)型,也會(huì)用auto進(jìn)行替換。
三、基于范圍的for循環(huán)
??C++98中遍歷一個(gè)數(shù)組:
void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)//通過(guò)下標(biāo)訪問(wèn)
array[i] *= 2;
for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p)//通過(guò)指針訪問(wèn)
cout << *p << endl;
}
??C++98中遍歷一個(gè)數(shù)組:
?對(duì)于一個(gè)有范圍的集合而言,由程序員來(lái)說(shuō)明循環(huán)的范圍是多余的,有時(shí)候還容易犯錯(cuò)誤。因此C++11中引入了基于范圍for循環(huán)。for循環(huán)后的括號(hào)由冒號(hào)“ : ”分為兩部分:第一部分是范圍內(nèi)用于迭代的變量,第二部分則表示被迭代的范圍。
void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)//加引用可以對(duì)后面的值修改
e *= 2;
for(auto e : array)
cout << e << " ";
return 0;
}
3.1 范圍for的使用條件
- for循環(huán)迭代的范圍必須是確定的
- 迭代的對(duì)象要實(shí)現(xiàn)++和==的操作
?對(duì)數(shù)組而言,就是數(shù)組中第一個(gè)元素和最后一個(gè)元素的范圍;對(duì)于類(lèi)而言,應(yīng)該提供begin和end方法,begin和end就是for循環(huán)的迭代范圍。范圍for本質(zhì)上是迭代器,支持迭代器就支持范圍for。
void Text(int arr[])//arr本質(zhì)上只是一個(gè)地址,沒(méi)有范圍
{
for (auto a : arr)//錯(cuò)誤
{
cout << a << endl;
}
}
四、指針空值nullptr
?良好的編程習(xí)慣要求我們,在聲明一個(gè)變量時(shí)最好給該變量一個(gè)合適的初始值,否則可能出現(xiàn)不可預(yù)料的錯(cuò)誤,比如未初始化的指針。如果一個(gè)指針沒(méi)有合法的指向,我們一般會(huì)把它置空。
??回顧NULL:
void f(int)
{
cout << "f(int)" << endl;
}
void f(int*)
{
cout << "f(int*)" << endl;
}
int main()
{
f(0);
f(NULL);
return 0;
}
?上述代碼的本意是:希望通過(guò)f(NULL);
去調(diào)用void f(int*)
,但是通過(guò)執(zhí)行結(jié)果可以看出,f(NULL);
調(diào)用的是void f(int)
。這是因?yàn)?code>NULL被定義成了0,且C++98中規(guī)定,字面常量0,既可以是一個(gè)整型數(shù)字,也可以是無(wú)類(lèi)型的指針(void*)常量,但是編譯器默認(rèn)情況下將其看成一個(gè)整型常量,如果要將其按照指針的方式來(lái)使用,必須對(duì)其進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換(void*)0
。
??認(rèn)識(shí)nullptr:
?nullptr
用來(lái)表示指針空值,因?yàn)閚ullptr是C++11作為新關(guān)鍵字引入的,所以在使用的時(shí)候不需要包頭文件。C++11中,sizeof(nullptr)
和sizeof((void*)0)
所占字節(jié)數(shù)相同。
int main()
{
cout << sizeof(nullptr) << endl;
cout << sizeof((void*)0) << endl;
return 0;
}
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-593940.html
?今天的分享到這里就結(jié)束啦!如果覺(jué)得文章還不錯(cuò)的話,可以三連支持一下,您的支持就是春人前進(jìn)的動(dòng)力!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-593940.html
到了這里,關(guān)于【C++雜貨鋪】?jī)?nèi)聯(lián)函數(shù)、auto、范圍for、nullptr的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!