之前沒有碰到過這類情況,也不知道實際工程中有什麼奧妙,先來一個小的測試例子看一下運行結果:
int a = 1;
int b = 2;
int *tmp = &a;
int *p = tmp;// 第二種情況:int *&p = tmp;(此既是指向指針的引用)
p = &b;
*p = 5;
1、測試此時的a, b , *tmp, *p分別是什麼: a = 1, b = 5, *tmp = 1, *p = 5;
2、如果是上述第二種情況,即指向指針的引用,那麼這些變量又該是什麼值呢?答案是:
a = 1, b = 5, *tmp = 5, *p = 5;
這是因為指向指針的引用,不僅改變了指針所指的對象,也改變了指針本身。
下面以Essential C++ P177的代碼舉例:
該代碼是為了刪除一個二叉樹中等於某個值的節點:
1 void BTnode::remove_value( const int& val, BTnode *& prev ) //二叉有序樹中刪除節點值_val == val的節點
2 {
3 if ( val < _val ) //往左子樹遍歷查找
4 {
5 if ( !_lchild )
6 {
7 return; //不在此二叉樹中
8 }
9 else _lchild->remove_value( val, _lchild );
10 }
11 else
12 if ( val > _val ) // 往右子樹遍歷查找
13 {
14 if ( !_rchild )
15 {
16 return; //不在此二叉樹中
17 }
18 else _rchild->remove_value( val, _rchild );
19 }
20 else
21 { //哈哈!~找到了~就是你啦!!
22 if ( _rchild ) //看看這個要被刪除的節點是否有右孩子
23 { //果然有~~有點小麻煩了~~哎
24 prev = _rchild;
25 if ( _lchild ) //要刪除的節點還有左孩子~得想辦法把左孩子弄到右子樹下面去,這樣才能刪除我這個節點
26 {
27 if ( !prev->_lchild ) //看看右子樹是否有一堆左孩子
28 {
29 prev->_lchild = _lchild;
30 }
31 else BTnode::lchild_lead(_lchild, prev->_lchild);//遍歷到右子樹最左節點
32 }
33 }
34 else prev = _lchild;
35 delete this; //不用怕刪除了本節點以後,我的孩子們連不到我的父輩節點們~~一句prev = _rchild解決了一切~~
36 }
37 }
上面代碼中紅色部分是最關鍵的地方,比如下面這棵樹:
其中的null是沒有節點(我這樣加個null是為了讓6看起來是右孩子)。
在這個圖裡,我要刪除5節點。若函數中參數是指針,而不是指向指針的引用。那麼上述程序,就會造成刪除了5節點以後,二叉樹斷成兩部分。(prev = _rchild;這裡我們只把prev重新改變為_rchild的值,而並沒有改變5這個地址所指向的值,但我們程序中這一句就要讓5的地址也改變)
而如果是指向指針的引用,prev = _rchild;這一句就會把5這個地址賦值為6的地址,這樣刪除5(即delete this;)之後就不會造成二叉樹的斷鏈問題。
Essential C++ P177是這麼描述的:
為什麼我們將prev以一個reference to pointer來傳遞呢?難道用單純的pointer傳遞還不夠嗎?不,不夠!以pointer來傳遞,我們能夠更改的是該pointer所指之物,而不是pointer本身。為了該表pointer本身,我們必須再加一層間接性。如果將prev聲明為reference to pointer,我們不但可以改變pointer本身,也可以改變由此pointer指向的對象。
摘自 ziyoudefeng