C++中的按引用和按值传参数问题
问题描述
今天朋友问我关于C++对象中的this的问题,大概的代码就是
return *this = *this + n;
我没系统学过C++,也很是困惑,主要有以下几点:
- *this + n 是哪一个优先级高
- 为什么要用传引用
*this + n 哪个的优先级高
这个问题比较好解决,这里很明显是吧this加上了n个对象的长度,得到了的地址。相似的,在*p + n; *p++; 都是先加地址。
为什么要用传引用
我们都知道按引用传参数,是把传入的参数的内存空间完全复制给了参数,这样参数就有了和调用函数之前的变量一样的地址,一样的空间,只是名字不一样。那么传值之后,取这个值得地址是不是也行呢?于是我写了一下两个程序做了实验:
#include <iostream>
int reference(int &num);
int main(){
int num[] = {1,2,3,4};
reference(num[0]);
}
int reference(int &num){
return *&num = *&num + 1;
}
#include <iostream>
int copy(int num);
int main(){
int num[] = {1,2,3,4};
reference(num[0]);
}
int copy(int num){
return *&num = *&num + 1;
}
我的猜想就是:
-
传值进去之后,%rdi 里的内容是(%rsp),也就是寄存器里放着这个变量的值;
-
传引用,%rdi里的内容应该是%rsp,也即放着这个变量的地址
于是我在Debian 9.5 x86-64 objdump 看了两个程序的汇编代码,两段代码分别如下:
push %rbp
mov %rsp,%rbp
sub $0x10,%rsp
movl $0x1,-0x10(%rbp)
movl $0x2,-0xc(%rbp)
movl $0x3,-0x8(%rbp)
movl $0x4,-0x4(%rbp)
lea -0x10(%rbp),%rax
mov %rax, %rdi
callq <reference>
push %rbp
mov %rsp,%rbp
sub $0x10,%rsp
movl $0x1,-0x10(%rbp)
movl $0x2,-0xc(%rbp)
movl $0x3,-0x8(%rbp)
movl $0x4,-0x4(%rbp)
mov -0x10(%rbp),%eax
mov %eax, %edi
callq <copy>
main函数里只有一个区别,reference(int &num)
是把num的地址传进去了,相当于reference(int* num)
,两者的区别只是C++对传地址进行了封装,在调用按引用传参的函数的时候,只需要穿进去值,即reference(num[0])
;后者则需要把地址传进去,即reference(num)
;
而copy(int num)
则仅仅是传进去值,在copy函数里,如果需要使用到这个变量的地址,函数将会把%rdipush到栈上,取到的地址也是这个新变量的地址,这个变量和调用者的变量只有一个联系,值是一样的,如果对这个新变量进行修改,是不会影响旧变量的。