C/C++: C++中引用和指针的区别

这篇文章引用自Stack Overflow上的一篇回答:What are the differences between a pointer variable and a reference variable in C++?。同时加进去了一些我的思考

区别

  • 直观上来看,两者的使用形式不同。在使用指针时,若我们想要对其指向数据赋值,需要使用*操作符。例如*p=4,而使用引用的话,直接进行复制操作就行了。int &ri = i; ri = 4;。这种形式上的简化可以带来很大的便利性。
  • 另一个形式的不同在于参数传递时。对于指针而言,在调用形如void f(int *i)的函数时,应当写作f(&i)。而对于引用而言,在调用形如void f(int& i)时,只需要写作f(i)
  • 一个指针变量可以被任意地再次赋值,而引用不可以
  • 指针可以指向空地址,而引用总是指向一个对象
  • 对于引用,无法用&进行取地址操作
  • 对于引用,无法使用算数方法叠加偏移来获取临近地址(but you can take the address of an object pointed by a reference and do pointer arithmetics on it)
  • 有回答提到,引用其实本质上就是const pointer 。不过区别还是存在的。静态指针本身也是可以为空的,但是引用则必然指向一个有效的对象,所以,在形参上使用引用形式可以确保该参数不为空。
  • 在性能层面,二者几乎没有区别:

C++标准并未规定编译器应当以何种方式来实现引用,不过几乎所有的C++编译器都是通过指针来实现引用。如果没有特殊优化,那么引用和指针在消耗的内存上是一样的

引用的设计思想(我的思考)

从上面我们列出的一系列引用和指针的不通之处,我们不难看出引用的设计的两个目的:一是形式的便利性,二是程序运行的安全性。

便利性

使用引用时,可以省去大量的*&符号,使得程序的形式更加简洁。在C++中,这种便利性,也使得操作符重载可以更加自然。例如我们有如下定义的枚举类型

enum day {
    Sunday, Monday //,...
}

如果我们想要该枚举类型支持++操作符,那么我们需要重载这一操作符。如果声明为

day operator++ (day d);

显然无法实现我们的意图。按照传统的C++的想法,此时可以引入指针机制,将操作符重载函数声明为

day operator++ (day* day);

这样声明虽然能够实现我们的功能了,但是我们在使用这个操作符时不得不更改为++&x。这看起来比较诡异。此时使用引用机制就能完美的解决这个问题

day operator++(day& day);

调用的时候使用++x就行了。

这里我们用引用机制完美的解决了这个问题。但是将这一参数形式引入到普通函数的定义上是不合适的。在普通的函数定义中,如果参数是指针式的,那么我们在传递参数的时候需要显式的使用到&。这可以提醒我们我们传递的是指针,意味着这将可能导致我们传递的变量可能在函数内部被修改。在采用引用形式后,这一隐含信息就难以发现了。

安全性

由于引用不能是空的,而且不可以被再次赋值而指向另一个对象,这个特性可以带来变成时候的稳健性,使得过去一些在运行阶段才会暴露出的bug(例如像一个逻辑上不接受NULL的函数传入了NULL参数)能够在编译阶段暴露处理啊。

你可能感兴趣的:(C/C++: C++中引用和指针的区别)