声明
指针对应的英文单词是pointer,引用对应的是reference
在英文中,当我们提到多个同一类型的对象时,我们通常会在这个对象名称后面加上“s”来表示复数形式。对于“pointer”和“reference”这两个词来说,也是如此。
当你看到“pointers”时,它表示的是多个指针。例如,在编程中,你可能会有多个指针变量,每个都指向内存中的不同位置。同样地,“references”表示的是多个引用。
所以,加“s”是为了表示这些概念在数量上是多个,而不是单个。
指针和引用
pointers 和references 看起来很不一样(pointers 使用“*”和“>”操作符,references则使用“.”),但它们似乎做类似的事情。不论pointers 或是references都使你得间接参考其他对象。
那么,何时使用哪一个?你心中可有一把尺?
区别1——没有空引用,但有空指针
首先你必须认知一点,没有所谓的null reference。
一个reference必须总代表某个对象。所以如果你有一个变量,其目的是用来指向(代表)另一个对象,但是也有可能它不指向(代表)任何对象,那么你应该使用pointer,因为你可以将pointer设为null。
换个角度看,如果这个变量总是必须代表一个对象,也就是说如果你的设计并不允许这个变量为null,那么你应该使用reference。
“但是等等”你说,“下面这样的东西,底层意义是什么呢?”
char *pc = 0;//将 pointer 设定为null。
char& rc = *pc;//让 reference 代表null pointer 的解引值。
哦,这是有害的行为,其结果不可预期(C++对此没有定义),编译器可以产生任何可能的输出,而写出这种代码的人,应该与大众隔离,直到他们允诺不再有类似行为。
如果你在你的软件中还需担心这类事情,我建议你还是完全不要使用references的好,要不就是另请一个比较高明的程序员来负责这类事情。从现在起,我们将永远不再考虑“reference 成为null”的可能性。
由于reference 一定得代表某个对象,C++因此要求references必须有初值:
string& rs;//错误!references 必须被初始化。
string s("xyzzy");
string& rs = s;//没问题,rs指向s。
但是pointers 就没有这样的限制:
string *ps;
//未初始化的指针,有效,但风险高。
“没有所谓的null reference”这个事实意味使用references可能会比使用pointers更富效率。这是因为使用reference 之前不需要测试其有效性:
void printDouble(const double& rd)
{
cout << rd;
// 不需要测试rd,它一定代表某个double。
}
如果使用 pointers,通常就得测试它是否为null:
void printDouble(const double *pd)
{
if (pd)
cout << *pd;
//检查是否为 null pointer。
}
区别2——引用一旦绑定不可修改,而指针可以
Pointers和references之间的另一个重要差异就是,pointers 可以被重新赋值,指向另一个对象,reference却总是指向(代表)它最初获得的那个对象:
string s1("Nancy");
string s2("Clancy");
string& rs= sl;//rs 代表s1。
string *ps= &s1;// ps 指向 s1。
rs =s2;//rs 仍然代表s1,
// 但是s1的值现在变成了“Clancy”。
ps= &s2;
// ps 现在指向 s2,
//s1没有变化。
一般而言,当你需要考虑“不指向任何对象”的可能性时,或是考虑“在不同时间指向不同对象”的能力时,你就应该采用pointer。前一种情况你可以将pointer设为null,后一种情况你可以改变pointer 所指对象。而当你确定“总是会代表某个对象”,而且“一旦代表了该对象就不能够再改变”,那么你应该选用reference。
还有其他情况也需要使用reference,例如当你实现某些操作符的时候。
最常见的例子就是operator[]。这个操作符很特别地必须返回某种“能够被当做assignment 赋值对象”的东西:
vector<int> v(10);
// 产生一个 int vector,大小为10。
// vector 是C++标准程序库
//提供的一个template。
v[5] =10;
// assignment 的赋值对象是operator[]的返回值。
如果operator[]返回pointer,上述最后一个语句就必须写成这样子:
*v[5] =10;
但这使v看起来好像是个以指针形成的vector,事实上它不是。为了这个因素,你应该总是令operator[]返回一个reference。
因此,让我做下结论:
- 当你知道你需要指向某个东西,而且绝不会改变指向其他东西,或是当你实现一个操作符而其语法需求无法由pointers达成,你就应该选择references。
- 任何其他时候,请采用pointers。