細說引用和指標

GeekWay發表於2012-09-28

[文獻參考]

《C++ Primer (第4版)》Stanley B.Lippman 著 ——人民郵電出版社

《c++語言程式設計(第4版)》 鄭莉 董源 何江舟 著——清華大學出版社

<C++程式設計教程(第二版)>》錢能著 ——清華大學出版社


   引用和指標有許多相似之處,例如它們都可以避免值複製的發生,從而減少函式呼叫時資料傳遞的開銷。那麼它們在深層中又有什麼聯絡嗎?

    在程式執行中,變數只能依靠地址來區別。因此,只有通過儲存被引用變數的地址,在執行時才能準確定位被引用的變數。

    引用本身所佔用的岑村空間中,儲存的就是被引用變數的地址,這和指標變數所儲存的內容具有相同的性質。

    指標式一種底層的機制,引用則是一種較高層的機制,在語言概念上引用是另一變數的“別名”,把地址這一概念隱藏起來了(所以對引用取地址獲得的時被引用變數的地址,而非引用本身的地址)。它們的差異主要在語言形式上,實際上都是靠儲存地址來實現的。

    引用與指標的顯著區別是,普通指標可以被多次賦值,即是可以多次更改它所指向的物件,二引用只能在初始化時指定被引用的物件,去後不能更改,所以,引用的功能具有指標常量的性質。

下圖為它們的對應關係:

操作 T型別的指標常量 對T型別的引用
定義並用v初始化(v是T型別變數) T * const p = &v; T &r = v;
取v的值 *p r
訪問成員m p->m r.m
讀取v的地址 p &r


可以肯定地說,能用引用實現的功能,用指標都可以實現。

既然這樣,為什麼還要引入引用這一概念呢?

指標是一種兼顧C語言特性的底層機制,正因為其底層,使用起來很靈活,功能強大。然而,正因為太過靈活,反而變得不好用。考慮一下情況:

①如果希望使用指標作為函式引數達到資料雙向傳遞或減少傳遞開銷的目的,在主調函式中需要用“&”傳遞引數,在被呼叫函式中需要用“*”訪問資料,程式難免顯得太過繁瑣。

②編譯器不會檢查指標越界,有些情況下不需要指標的算術運算,這時如果對指標進行算術運算,會造成不必要的麻煩。

為了能夠滿足更加方便、安全的處理資料雙向傳遞,減少引數傳遞開銷這樣的簡單需求,引用這一概念被引入了C++中。

下面通過swap函式可比較指標和引用書寫和使用上的繁簡:

//使用指標常量 
void swap(int * const pa, int * const pb)
{
	int temp = *pa;
	*pa = *pb;
	*pb = *pa;
}

int main()
{
	int a, b;
	...
	swap(&a, &b);
	...
	return 0;
}


//使用引用 
void swap(int &ra, int &b)
{
	int temp = ra;
	ra = rb;
	rb = ra;
}

int main()
{
	int a, b;
	...
	swap(a, b);
	...
	return 0;
}


對於資料引數傳遞、減少大物件的引數傳遞開銷這兩個用途來說,引用可以很好的代替指標,使用引用比使用指標更加簡潔、安全。


但有些時候,引用還不能完全替代指標,具體如下:

(1)如果一個指標所指向的物件,需要用分支結構加以確定,或者在中途需要改變它所指向的物件,那麼在他初始化之後需要為它賦值,此時引用不能勝任。

(2)有時指標的值可能是一個空指標,空指標在一些情況下表達特定的含義,如ctime標頭檔案中的time函式。

(3)使用指標函式,而沒有函式引用。

(4)用new動態建立的物件或陣列,需要用指標來儲存它的地址。

(5)以陣列形式傳遞大批量資料時,需要用指標型別接收引數。




相關文章