內聯函數
概念
以inline修飾的函數叫做內聯函數,編譯時C++編譯器會在調用內聯函數的地方展開,沒有函數壓棧的開銷, 內聯函數提升程序運行的效率
- 函數前增加inline關鍵字將其改成內聯函數,在編譯期間編譯器會用函數體替換函數的調用。
反匯編中依舊有call指令語句
為什么?
因為代碼在Debug模式下,把它調回release模式
所以需要在release模式下,查看編譯器生成的匯編代碼中是否存在call Add
因為代碼在實際中沒有什么作用,所以編譯器把代碼忽略掉了。
并沒有出現call語句。
- 在debug模式下,需要對編譯器進行設置,否則不會展開(因為debug模式下,編譯器默認不會對代碼進行 優化,以下給出vs2013的設置方式)
然后再轉到反匯編就可以看到了。
特性
4. inline是一種以空間換時間的做法,省去調用函數額開銷。所以代碼很長或者有循環/遞歸的函數不適宜使 用作為內聯函數。
5. inline對于編譯器而言只是一個建議,編譯器會自動優化,如果定義為inline的函數體內有循環/遞歸等 等,編譯器優化時會忽略掉內聯。
6. inline不建議聲明和定義分離,分離會導致鏈接錯誤。因為inline被展開,就沒有函數地址了,鏈接就會找 不到。
宏的優缺點
宏:可以定義
常量函數
優點:
- 增強代碼的復用性
- 提高性能
缺點:
- 不方便調試宏。(因為預編譯階段進行了替換)
- 導致代碼可讀性差,可維護性差,容易誤用。
- 沒有類型安全的檢查
C++有哪些技術替代宏?
- 常量定義 換用const
- 函數定義 換用內聯函數
const關鍵字
auto簡介
在c語言中const修飾的是內容不能修改的變量
c++中const關鍵字修飾是把一個變量變量變成一個常量。而且此常量具有宏的屬性,就是替換。在代碼編譯期間進行替換。
下列程序中*pa和a的值各是多少?
const int a=10;
int *pa = ( int * )&a;
*pa=100;
cout<<a<<endl;
cout<<*pa<<endl;
auto關鍵字(C++11)
auto簡介
在早期C/C++中auto的含義是:使用auto修飾的變量,是具有自動存儲器的局部變量(具有自動銷毀功能 ),但遺憾的是一直沒有人 去使用它,大家可思考下為什么?
因為函數體的局部變量本身就在函數返回時自己銷毀,不需要多此一舉。
C++11中,標準委員會賦予了auto全新的含義即:auto不再是一個存儲類型指示符,而是作為一個新的類型指 示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時期推導而得。
int TestAuto(){return 10; }int main() {int a = 10; auto b = a;auto c = 'a';auto d = TestAuto();cout << typeid(b).name() << endl; cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;return 0;
}

定義了一個a的變量并賦了一個10.結構默認為int類型。
而定義一個變量b,并賦值3.14,結果類型為double。
注意
使用auto定義變量時必須對其進行初始化,在編譯階段編譯器需要根據初始化表達式來推導auto的實際類 型。因此auto并非是一種“類型”的聲明,而是一個類型聲明時的“占位符”,編譯器在編譯期會將auto替換為變 量實際的類型。
auto的使用細則
auto與指針和引用結合起來使用
用auto聲明指針類型時,用auto和auto*沒有任何區別,但用auto聲明引用類型時則必須加&
在同一行定義多個變量
當在同一行聲明多個變量時,這些變量必須是相同的類型,否則編譯器將會報錯,因為編譯器實際只對第一個 類型進行推導,然后用推導出來的類型定義其他變量。
void TestAuto(){ auto a = 1, b = 2; auto c = 3, d = 4.0; // 該行代碼會編譯失敗,因為c和d的初始化表達式類型不同 }
auto不能推導的場景
-
auto不能作為函數的參數
// 此處代碼編譯失敗,auto不能作為形參類型,因為編譯器無法對a的實際類型進行推導void TestAuto(auto a)
{} -
auto不能直接用來聲明數組
void TestAuto()
{
int a[] = {1,2,3};
auto b[] = {4,5,6};
} -
為了避免與C++98中的auto發生混淆,C++11只保留了auto作為類型指示符的用法
-
auto在實際中常見的優勢用法就是跟以后會講到的C++11提供的新式for循環,還有lambda表達式等進 行配合使用。
-
auto不能定義類的非靜態成員變量
-
實例化模板時不能使用auto作為模板參數
基于范圍的for循環(C++11)
在C++98中如果要遍歷一個數組,可以按照以下方式進行
void TestFor() {int array[] = { 1, 2, 3, 4, 5 }; for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i) array[i] *= 2;for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p) cout << *p << endl;}
對于一個有范圍的集合而言,由程序員來說明循環的范圍是多余的,有時候還會容易犯錯誤。因此C++11中引 入了基于范圍的for循環。for循環后的括號由冒號“ :”分為兩部分:第一部分是范圍內用于迭代的變量,第二 部分則表示被迭代的范圍。
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array) e *= 2;for(auto e : array) cout << e << " ";
而用auto e 則不會改變數組中的內容,因為e只是拷貝,而要想改變,必須用引用。
范圍for的使用條件
1. for循環迭代的范圍必須是確定的
對于數組而言,就是數組中第一個元素和后一個元素的范圍;對于類而言,應該提供begin和end的方法, begin和end就是 for循環迭代的范圍。
2. 迭代的對象要實現++和==的操作。
. 指針空值nullptr(C++11)
平常我們一般把沒有明確指向的指針指空。
NULL可能被定義為字面常量0,或者被定義為無類型指針(void)的常量。*
nullptr 與 nullptr_t
:為了避免混淆,C++11提供了nullptr, 即:nullptr代表一個指針空值常量。nullptr是有類型的,其類型為nullptr_t,僅僅可以被隱式轉化為指針類 型,nullptr_t被定義在頭文件中:
**typedef decltype(nullptr) nullptr_t;**
注意:
- 在使用nullptr表示指針空值時,不需要包含頭文件,因為nullptr是C++11作為新關鍵字引入的。
- 在C++11中,sizeof(nullptr) 與 sizeof((void*)0)所占的字節數相同。
- 為了提高代碼的健壯性,在后續表示指針空值時建議好使用nullptr。