1. 程式人生 > >C++引用及C11的一些關鍵字

C++引用及C11的一些關鍵字

C++引用及C11的一些關鍵字

引用

引用概念

	引用不是定義一個新的變數,而是給已知的變數取一個別名,定義一個引用變數之後,編譯器並不會在內部為它開闢記憶體,而是和其引用變數共用一塊記憶體空間。
	型別& 引用變數 = 引用實體;

引用特性

引用變數在定義時必須初始化
同一個引用變數不能引用多個實體
同一個變數可以被多次引用

int a = 10;
int b = 20;
//int &ra;  在編譯時會出錯。
int &ra = a;
int &rb = a;
//int &rb = b; 編譯時報錯。
printf("%p, %p, %p\n", &a, &ra, &rb);

在這裡插入圖片描述

由此可見,引用變數與引用實體指向通一塊記憶體。

const常引用

我們知道被const修飾的變數不能被隨意修改,那該如何引用被const修飾的變數?這就需要常引用。

const int a = 10;
//int& ra = a;
const int& raa = a;

通過編譯可以知道,直接用一般引用是不能引用const所修飾的變數的,必須顯式宣告引用也是const型別的。

double d = 12.34;
//int& rd = d;
const int&rdd = d;

double型別的不能被int所引用,但是卻可以被const int所引用,這是為什麼呢。
所謂引用就是將rdd和d指向同一塊記憶體空間,但是因為兩者型別不同,這中間肯定有型別強轉,所以rdd只指向double整數的那塊空間,但是此時這塊空間不是完整的d,我們也不知道名字,所以編譯器就將這塊記憶體當做常量來處理,這樣用const修飾就可以被引用。

引用與指標

我們可以通過引用與指標來分別修改一個變數的值

int a = 10;
int& ra = a;
int *pa = NULL;

ra = 20;
*pa = 20;


從彙編程式碼上看,指標和引用在本質上並沒有區別,也可以說引用底層實現原理就是使用指標。既然兩者底層實現基本都相同,所以在效率上兩者也是不相上下的。
回到我們之前說的,一個引用只能引用一個變數,但是一個指標卻可以指向任意地址,既然兩者底層實現都相同,那麼引用應該也可以引用多個變數才是。
我們可以把引用int& ra = a;理解為 int * const ra = &a,用一個const來修飾引用變數,這樣引用變數的值就不能被隨便修改。

引用在定義時必須初始化,指標可以不同
引用在引用一個實體後不能再引用其他實體,但是指標可以指向任意一個地址
在sizeof中,引用大小為引用引用型別的大小,指標始終是地址空間所佔的位元組數
引用自加是給變數本身加一,但是指標是所指向型別的大小加一
有多級指標,但是沒有多級引用
在訪問實體時,指標需要顯式解引用,但是引用編譯器自己實現
沒有NULL引用,但是有NULL指標
使用引用比使用指標更安全

行內函數

	有些程式碼塊很小的函式,在呼叫時也需要開闢棧幀,這無疑會降低程式執行的效率,所以C++允許以inline關鍵字宣告的函式作為行內函數,編譯器會在呼叫行內函數的地方展開,沒有函式壓棧的開銷,以此來提升程式執行的效率。
	行內函數是一種典型的以空間換取時間的做法,所以程式碼很長或者遞迴的函式不適合作為行內函數
	inline關鍵字對於編譯器來說只是一個建議,如果函式體內有迴圈遞迴,編譯器會自動忽略內聯。

巨集與巨集函式

巨集與巨集函式增強了程式碼的複用性,並且也提高了效能,但是對於巨集來說,在預處理階段已經被編譯器替換,無法檢查巨集函式的型別以及返回值,不方便除錯,對於++,–等操作因為多次呼叫導致結果出錯,這無疑大大降低了巨集的實用性。
但是在C++中,可以用行內函數來替換巨集,同樣可以達到目的。

C++11的一些關鍵字

auto

C++11中,賦予了auto全新的含義即:auto不再是一個儲存型別指示符,而是作為一個新的型別指示符來指示編譯器,auto宣告的變數必須由編譯器在編譯時期推導而得。

int a = 10;
auto b = a;
auto c = 'x';
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;

在這裡插入圖片描述
我們可以看到,使用auto關鍵字,編譯器自己推導變數型別。在使用auto時,必須對其初始化,編譯器在編譯階段需要根據初始化表示式來推導實際型別,所以auto並不是一種型別的宣告,而是一個型別宣告的佔位符。

auto的使用

1、auto與指標引用結合起來使用

int x = 10;
auto px = &x;
auto* ppx = &x;
auto& rx = x;

需要注意的是,使用auto宣告引用型別的話,必須在auto後面加上&,指標可以不用。
2、在同一行定義多個變數

auto a = 1, b = 2;
//auto c = 3, d = 4.0  編譯出錯,c和d的型別不同

在同一行宣告多個變數時,這些變數必須是相同的型別,否則編譯器就會報錯,編譯器會根據第一個推匯出來的型別來定義其他變數。
3、auto不能作為函式形參型別
4、auto不能直接宣告陣列。
5、auto與for迴圈搭配使用

C++11新式for迴圈

在11中,迴圈常與auto搭配使用。for迴圈的條件有冒號分為兩部分,第一部分是範圍內用於迭代的變數,第二部分是用於迭代的範圍

int array[] = {1, 2, 3, 4, 5};
for(auto& a : array){
	a *= 2;
}
for(auto a : array){
	cout << a << " ";
}

與普通迴圈類似,可以用continue和break來控制迴圈。

指標控制nullptr

C++11用nullptr來表示控制指標,與之前NULL不同的是,NULL僅僅是一個巨集,但是nullptr是有型別的,表示一個指標空值常量。

typedef decltype(nullptr) nullptr_t;