指针和引用的区别
指针和引用的区别
指针和引用在 C++ 中都用于间接访问变量,但它们有一些区别:
- 指针是一个变量,它保存看另一个变量的内存地址;引用是另一个变量的别名,与原变量共享内存地址。
- 指针可以被重复赋值,指向不同的变量;引用在初始化后不能更改,始终指向同一个变量。
- 指针可以为 nullptr,表示不指向任何变量;引用必须绑定到一个变量(必须初始化),不能为 nullptr。
- 使用指针需要对其进行解引用以获取或修改其指向的变量的值;引用可以直接使用,无需解引用。
下面的示例展示了指针和引用的区别:
1 |
|
从汇编底层角度来解释 C++ 中引用的实现机制:指针和引用有什么区别
从汇编看引用和指针
引用是变量的别名,这是 C++ 语法规定的语义,而引用在汇编层面和指针没区别,引用被编译器当作 const 指针来进行操作。
分别用指针和引用来实现函数 swap():
1 | void swap(int* a, int* b) { |
gcc -S 输出swap()函数的汇编,指针版和引用版完全一样,以函数调用两个 swap() 也一样。
总结
- 引用只是 C++ 语法糖,可以看作编译器自动完成取地址、解引用的常量指针(必须初始化,不可修改)。
- 引用区别于指针的特性都是编译器约束完成的,编译成汇编代码就和指针一样。
- 由于引用只是指针包装了一下,所以也存在风险,下文有例。
- 引用由编译器保证初始化,使用起来较为方便(如不用检查空指针等)。
- 尽量用引用代替指针。
- 引用没有顶层 const 即
int& const,因为引用本身就不可变,所以再加顶层 const 也没有意义;但是可以有底层 const 即const int&,这表示引用所引用的对象本身是常量。 - 指针既有顶层 const (
int* const--指针本身不可变),也有底层 const (const int*--指针所指向的变量不变)。 - 有指针引用,是一个引用绑定到指针,但是没有引用指针。显然,因为指针本身也是一个变量,所以可以有指针引用;但很多时候指针存在的意义就是间接改变对象的值,而引用必须初始化且不可再修改,所以不能有引用指针。
- 指针和引用的自增、自减含义不同:指针是自增减是指针运算,而引用是代表所指向的对象自增减(语义上引用就是变量的别名,相当于是变量在操作,实际上编译器会自动解引用)。
#总结 -4. 例:
1 |
|
我们以指针申请内存空间存放一个 int,会输出一个随机值,不同的编译器给的值不一样,猜测是内存被申请前该地址存放的值,或编译器自定义的一个什么值,这无所谓。同时输出这块申请来的内存的地址。
然后通过指针解引用,为引用初始化,再通过指针释放这块内存,这里关于 delete 有问题,正如注释而言,如果delete 之后不写 a = nullptr,在 Dev5.11 中测试仍可通过对指针解引用 *a 来读取或修改这块地址的内容,而写了之后运行程序会在此异常中止。但 Visual Studio 即使不写 a = nullptr,delete 之后对指针 a 试图解引用也会触发异常。当然这不是我们讨论的重点。
关键在于通过指针释放内存后,引用 b 仍然保留地址,且可以正常读取和修改地址处存放的值,并不会触发异常。而此时这里属于已经被释放的内存,如果之后再用,这显然是不安全的。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 PEACE's Blog!




