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 使我們的向量不可修改,即只讀。