C++ 中的常量引用与普通参数传递
本文将讨论 const 引用和普通参数传递之间的区别。
为了更好地理解 const 引用,我们首先要了解按值传递、按引用传递和按 const 引用传递之间的区别。
在 C++ 中按值传递
在传递参数值之前,编译器使用虚拟变量创建其内存的副本,并传递其值。
#include <bits/stdc++.h>
using namespace std;
void fun(int num) { num = num + 10; }
int main() {
int n = 30;
fun(n);
cout << n << endl;
}
输出:
30
当参数 n
通过 fun()
函数时,编译器在 n
中创建内存副本。由于它是一个副本,所以函数不会修改 n
的原始值。
在这里,我们遇到两个缺点。我们无法更改它的值,并且创建了参数的副本,浪费了内存。
在 C++ 中通过引用传递
这种方法消除了按值传递方法的缺点。我们不是创建一个虚拟参数并传递它的值,而是传递变量的别名。
因此,不会浪费内存,并且由于传递了变量的别名,因此对函数中变量所做的任何更改都会得到反映。
#include <bits/stdc++.h>
using namespace std;
void fun(int &num) { num = num + 10; }
int main() {
int n = 30;
fun(n);
cout << n << endl;
}
n
的值在这里受到影响。
40
在 C++ 中使用常量引用传递
现在,当我们不想浪费任何内存并且不更改变量的值时,我们可以使用 const 引用。
#include <bits/stdc++.h>
using namespace std;
void fun(const int &num) { num = num + 10; }
int main() {
int n = 30;
fun(n);
cout << n << endl;
}
上面的代码将抛出编译错误,因为 num = num +10
作为 const 引用传递。因为是 const,所以参数变成只读的,不能改变 num
的值。
输出:
[Error] assignment of read-only reference 'num'
虽然我们提到当引用为 const 引用时参数的值不能改变,但还是有一些微妙但至关重要的区别。
如果一个参数是一个 const
引用,但传递的参数是 not const
,那么在函数调用期间参数的值可能会改变。
#include <bits/stdc++.h>
using namespace std;
void fun(const int &n) { const_cast<int &>(n) = 40; }
int main() {
int n = 30;
fun(n);
cout << n << endl;
}
我们观察到虽然传递的参数不是 const。函数 fun
可以在 cast 的帮助下改变它的值。
输出:
40
当使用 const 引用传递参数时,它包括取消引用的额外成本。最差的引用位置和编译器优化的机会几乎为零。
概括
语法 - 按值传递:
double fun(vector<double> my_vector); //pass by value
这里的底层对象或向量是使用其复制构造函数复制的。新对象分配了额外的内存,所有值和子对象都被单独复制和存储。
所以上面的函数将复制向量并对该向量的副本而不是原始向量本身进行更改。如果传递的对象或向量很大,则复制过程将变得非常繁琐,浪费我们的存储和 CPU 周期。
语法 - 通过引用传递:
double fun(vector<double> &my_vector); //pass by reference
底层向量没有被复制,并且传递了向量本身的内存地址,因此函数所做的更改将直接对原始向量进行。
这节省了内存和 CPU 周期
,因为没有分配新的内存,也没有调用(昂贵的)复制构造函数。
语法 - 通过常量引用传递:
double fun(const vector<double> &my_vector); //pass by const reference
上面的语法类似于通过引用传递,唯一的区别是我们不能修改基础值。这解决了不复制和不修改我们对象的值的问题。
这里的引用符号 (&
) 表示向量不应被复制,关键字 const 使我们的向量不可修改,即只读。