引言
-
string& 作爲函數參數的問題
你在使用cpp過程是否遇到過使用string&作爲函數參數,main調用的時候編譯失敗的問題?
例如下面這份簡單的代碼void func(string& a) { } int main() { func("12323"); }
編譯器提示如下
[Error] invalid initialization of non-const reference of type ‘std::string& {aka std::basic_string&}’ from an rvalue of type 'const char*
const & 類型
上面的代碼錯誤原因在於string&是一個引用類型,必須要有地址,而“asdfdsf”是const char*類型(是右值,可以理解爲不可修改的值),無法直接轉換到string&
簡單的修改成如下可以編譯通過
void func(const string& a) {
}
int main() {
func("12323");
}
如何理解func中的 a?
a是一種const string& 類型,調用func會先調用string的構造函數string(const char*)生成一個臨時變量,命名爲a,函數調用結束之後就會銷燬。
&& 類型
還有一個方案,修改爲右值引用類型
void func(string&& a) {
}
int main() {
func("12323");
}
三種引用的理解(左值引用 T & ; const引用 const T& ; 右值引用 T&&)
右值簡單可以理解爲沒有明確地址的值(或者是臨時值),常見的右值有整數,浮點數,字符,字符串,例如以下
1,1.23, 2324, ‘c’,“23423535”
int s() {
return 1234;
}
int main() {
int& f = s(); // 編譯失敗,左值引用必須要明確的內存地址
int&& f = s(); // 通過
cout << f<< endl;
}
-
爲什麼需要右值引用?
c/c++默認值傳遞,傳遞函數參數過程中如果沒有引用來修飾的話,會複製出一個臨時變量出來,這個變量函數調用結束會銷燬;而普通的引用只能接受有明確地址的變量,而右值引用接受沒有明確地址的變量(例如上面列舉的那些)
(代碼1)void func(string& a) { // 參數普通引用 b[0] = 'a'; } int main() { func("abcdefg"); // 不合法 string s; func(s); // 合法 }
(代碼2)
void func(string&& a) { // 參數右值引用 a[0] = 'a'; } int main() { func("abcdefg"); // 合法 string s; func(s); // 不合法 }
-
何爲左值引用(T&)
可以理解爲一個指針,只不過c語言中的指針需要用*來取值,->來進行訪問。引用簡化了這個過程,讓他使用起來更加的方便(和普通的類型一致)
函數參數傳遞引用相當於傳遞一個指針,可以避免不必要的構造函數。 -
何爲const引用(const T&)
可以理解爲const指針,const引用聲明後沒辦法修改內部的值(只能調用非const方法),除此之外const引用支持右值來構造
string& aa = “21324”; // 不合法 ,因爲"21324"沒有明確的地址
const string& bb = “sdfdf”; // 合法,會找到合適的構造函數
b[0] = ‘a’; // 不合法,不可寫入
cout << b[0] << endl; //合法,可以讀 -
何爲右值引用 (T &&)
例如普通的引用 int& a = 1234; 是編譯吧不通過的,因爲1234沒有明確地址空間
string c;
string& s = “abcdefg”; //不合法
string& a = c; //合法,c有明確的地址
string&& b = c; //不合法,只能用那些沒有明確地址的值來賦值,例如"abcdefg"
string&& d = “abcdefg”; // 合法 -
const T& 和 T&&右什麼區別?
兩者幾乎很相似,只不過const T&受到const的限制還有語義上的區別-
const T&可以既可以接受普通的變量,又可以接受右值,但是操作起來不方便(受到const的限制),如果想要方便的操作的話,需要使用const_cast 把它轉爲普通的引用。
void func(const string& a) { string& b = const_cast<string&>(a); } int main() { func("abcdefg"); }
使用T&&可以省略去轉換的過程
void func(const string& a) { string& b = const_cast<string&>(a); b[0] = 'a'; //合法的 } void func(string&& a) { //a是已經被轉換好的。 a[0] = 'a'; // 合法的 }
-
語義上,一般const修飾過的變量一般就認爲不可修改。(雖然可以修改但最好不要這麼做)
如果你想讓你的函數即可接受普通的左值,又可以接受臨時的變量,還想減少不必要的構造函數調用,可以這麼做。string& func(string& a) { a[0] = 's'; return a; } string& func(string&& a) { return func(a); // 這這裏調用 void func(string&) } int main() { cout << func("55555") << endl; // 調用 void func(string&&) string s = "6666"; cout << func(s) << endl; // 調用void func(string&) }
-
std::move (移動語義)
待補充
std::forward(完美轉發)
待補充