指针和引用 看起来非常不同 (指针使用
*“*”和
->“->”运算符,引用使用
.“.”),但它们似乎做着相似的事情。指针和引用都允许你间接地引用其他对象。那么,你如何决定何时使用一个,而不是另一个呢?
首先,要认识到没有空引用这样的东西。引用必须始终引用某个对象。因此,如果你的变量的目的是引用另一个对象,但可能没有对象可引用,则应将该变量设置为指针,因为这样你可以将其设置为 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[]返回一个引用。
因此,当你确定有东西可以引用,当你永远不想引用其他任何东西,并且当实现语法要求使指针的使用变得不可取的运算符时,引用是首选特性。在所有其他情况下,坚持使用指针。