C++:指针与引用的区别

这是一个老生常谈的问题了,废话不多说,开始!
那么指针与引用有什么区别呢?

答:几乎没有区别

相信学过c++的人几乎都可以回答:

 1. 指针是所指内存的地址
 2. 引用是别名
 3. 引用必须初始化,并且初始化后不能重新引用其它变量

但是引用是别名这是 C++ 语法规定的语义。那么到底引用在汇编层面和指针有什么区别呢?

答:无区别

下面我们从汇编层面解析代码,指针版与引用版本的交换函数:

// 指针版
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
// 引用版
void swap(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

引用版汇编:

__Z4swapRiS_:                           ## @_Z4swapRiS_
        .cfi_startproc
## %bb.0:
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp          
        .cfi_def_cfa_register %rbp
        movq    %rdi, -8(%rbp)     # 传入的第一个参数存放到%rbp-8  (应该是采用的寄存器传参,而不是常见的压栈)
        movq    %rsi, -16(%rbp)    # 第二个参数 存放到 %rbp-16
        movq    -8(%rbp), %rsi     # 第一个参数赋给 rsi
        movl    (%rsi), %eax       # 以第一个参数为地址取出值赋给eax,取出*a暂存寄存器
        movl    %eax, -20(%rbp)    # temp = a
        movq    -16(%rbp), %rsi    # 将第二个参数重复上面的
        movl    (%rsi), %eax
        movq    -8(%rbp), %rsi    
        movl    %eax, (%rsi)       # a = b
        movl    -20(%rbp), %eax    # eax = temp
        movq    -16(%rbp), %rsi
        movl    %eax, (%rsi)       # b = temp
        popq    %rbp
        retq
        .cfi_endproc
                                        ## -- End function

指针版汇编:

__Z4swapPiS_:                           ## @_Z4swapPiS_
        .cfi_startproc
## %bb.0:
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register %rbp
        movq    %rdi, -8(%rbp)
        movq    %rsi, -16(%rbp)
        movq    -8(%rbp), %rsi
        movl    (%rsi), %eax
        movl    %eax, -20(%rbp)
        movq    -16(%rbp), %rsi
        movl    (%rsi), %eax
        movq    -8(%rbp), %rsi
        movl    %eax, (%rsi)
        movl    -20(%rbp), %eax
        movq    -16(%rbp), %rsi
        movl    %eax, (%rsi)
        popq    %rbp
        retq
        .cfi_endproc
                                        ## -- End function

看到了吧,几乎没有区别,可以说引用只是一层语法糖。
总结:

  • 1、引用只是c++语法糖,可以看作编译器自动完成取地址、解引用的常量指针
  • 2、用区别于指针的特性都是编译器约束完成的,一旦编译成汇编就和指针一样
  • 3、由于引用只是指针包装了下,所以也存在风险,比如如下代码:
int *a = new int;
int &b = *a;
delete a;
b = 12;    // 对已经释放的内存解引用
  • 4、引用由编译器保证初始化,使用起来较为方便(如不用检查空指针等)
  • 5、尽量用引用代替指针
  • 6、引用没有顶层 const (引用本身不可变) 即int & const,因为引用本身就不可变,所以在加顶层 const 也没有意义;但是可以有底层 const ()即 const int&,这表示引用所引用的对象本身是常量
  • 7、指针既有顶层const(int * const–指针本身不可变),也有底层const(const int *–指针所指向的对象不可变)
  • 8、有指针引用–是引用,绑定到指针, 但是没有引用指针–这很显然,因为很多时候指针存在的意义就是间接改变对象的值。但是引用本身的值我们上面说过了是所引用对象的地址,但是引用不能更改所引用的对象,也就当然不能有引用指针了。
  • 9、指针和引用的自增(++)和自减含义不同,指针是指针运算, 而引用是代表所指向的对象对象执行++或–
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值