相同点:两者都是在被调用函数中的栈区开辟一个空间,往这块空间填入一个值
值传递
- 值传递:在函数调用时候,会触发一次参数的拷贝动作,因此对参数的修改不会影响原始的值,如果是较大的对象,复制整个对象,效率较低
void modify_value(int value) {
value = 100; // 只会修改函数内部的副本,不会影响原始变量
}
int main() {
int a = 20;
modify_value(a);
std::cout << a; // 20,没变
return 0;
}
引用传递
- 引用传递:函数调用时,函数接收的就是参数的引用,不会触发参数的拷贝动作,效率较高,但对参数的修改会直接作用于原始的值
void modify_value(int& value) {
value = 100; // 修改引用指向的原始变量
}
int main() {
int a = 20;
modify_value(a);
std::cout << a; // 100,因为是引用传递,所以这里已经改为了100
return 0;
}
从编译的角度看,生成符号表的时候,会在符号表中填入变量名和对应的地址。值传递的形参对应的地址是实参变量的地址,而这个地址中的内容是可以改变的。而引用变量名对应的地址是引用对象的地址,符号表一经生成无法改变,所以引用变量不能更改引用的对象。
实际使用
什么场景下使用引用传递?
🔥 避免不必要的数据拷贝:对于比较大的对象参数 (比如 std::vector、std::string、std::list),因为拷贝会导致大量的内存和时间开销。而引用传递可以避免这些开销。
允许函数修改实参原始值:有时候,我们就是希望函数能够直接修改传入的变量值,这时使用引用传递很合理。
什么场景下使用值传递?
🔥 小型数据结构:对于 int、char、double、float这种基础数据类型,可以直接简单的使用值传递。 不希望函数修改实参:有时候,我们需要修改变量数据,但是又不希望修改原始值,可以考虑使用值传递。
在实际代码中,为了减少拷贝,我们通过是使用
const auto &,防止传递的数据发生变化,但是有时候const也会出现点问题,有时候也会去掉,但是这个需要我们函数里面没对实参作出修改,具体问题具体分析