指標和引用 看起來非常不同 (指標使用
*“*”和
->“->”運算子,引用使用
.“.”),但它們似乎做著相似的事情。指標和引用都允許你間接地引用其他物件。那麼,你如何決定何時使用一個,而不是另一個呢?
首先,要認識到沒有空引用這樣的東西。引用必須始終引用某個物件。因此,如果你的變數的目的是引用另一個物件,但可能沒有物件可引用,則應將該變數設定為指標,因為這樣你可以將其設定為 null。另一方面,如果變數必須始終引用一個物件,即,如果你的設計不允許該變數為空的可能性,那麼你可能應該將該變數設定為引用。
“但是等等,”你可能會疑惑,“像這樣的幕後操作呢?”
1 2 3
|
char *pc = 0; // set pointer to null
char& rc = *pc; // make reference refer to
// dereferenced null pointer
|
嗯,這純粹是邪惡的。結果是未定義的(編譯器可以生成任何他們喜歡的輸出),並且應該避免編寫這種程式碼的人,直到他們同意停止和放棄。如果你必須擔心軟體中的此類事情,最好完全避免使用引用。要麼找到更好的一類
程式設計師 一起工作。我們將在此忽略引用可以是
null的可能性。
因為引用必須引用一個物件,
C++ 要求必須初始化引用
1 2 3 4
|
string& rs; // error! References must
// be initialized
string s("xyzzy");
string& rs = s; // okay, rs refers to s
|
指標不受此限制
1 2
|
string *ps; // uninitialized pointer:
// valid but risky
|
沒有空引用這一事實意味著使用引用比使用指標更有效。這是因為在使用引用之前,無需測試引用的有效性
1 2 3 4
|
void printDouble(const double& rd)
{
cout << rd; // no need to test rd; it
} // must refer to a double
|
另一方面,通常應針對 null 測試指標
1 2 3 4 5 6
|
void printDouble(const double *pd)
{
if (pd) { // check for null pointer
cout << *pd;
}
}
|
指標和引用之間的另一個重要區別是指標可以被重新賦值以引用不同的物件。但是,引用始終引用初始化它的物件
1 2 3 4 5 6 7 8 9 10 11 12
|
string s1("Nancy");
string s2("Clancy");
string& rs = s1; // rs refers to s1
string *ps = &s1; // ps points to s1<a name="31186"></a>
rs = s2; // rs still refers to s1,
// but s1's value is now
// "Clancy"
ps = &s2; // ps now points to s2;
// s1 is unchanged
|
一般來說,每當需要考慮到沒有東西可引用(在這種情況下,你可以將指標設定為 null)或者每當需要能夠在不同的時間引用不同的東西(在這種情況下,你可以更改指標指向的位置)時,都應該使用指標。每當你確定總會有一個物件可以引用,並且你也知道一旦你引用了該物件,你永遠不想引用其他任何東西時,你應該使用引用。
還有一種情況下你應該使用引用,那就是當你實現某些運算子時。最常見的例子是
operator[]。此運算子通常需要返回可以作為賦值目標的內容
1 2 3 4 5
|
vector<int> v(10); // create an int vector of size 10;
// vector is a template in the
// standard C++ library
v[5] = 10; // the target of this assignment is
// the return value of operator[]
|
如果 operator[] 返回一個指標,那麼最後一條語句必須這樣寫
*v[5] = 10;
但這使得 v 看起來像是一個指標向量,但事實並非如此。因此,你幾乎總是想要
operator[]返回一個引用。
因此,當你確定有東西可以引用,當你永遠不想引用其他任何東西,並且當實現語法要求使指標的使用變得不可取的運算子時,引用是首選特性。在所有其他情況下,堅持使用指標。