引用聲明
聲明具名變量爲引用,即既存對象或函數的別名。
左值和右值的概念
左值是可以放在賦值號左邊可以被賦值的值;左值必須要在內存中有實體;
右值當在賦值號右邊取出值賦給其他變量的值;右值可以在內存也可以在CPU寄存器。
一個對象被用作右值時,使用的是它的內容(值),被當作左值時,使用的是它的地址。
語法
聲明具名變量爲引用,即既存對象或函數的別名。
& attr(可選) 聲明符 (1)
&& attr(可選) 聲明符 (2) (C++11 起)
- 左值引用聲明符:聲明 S& D; 將 D 聲明爲到 聲明說明符序列 所確定的類型 S 的左值引用。
- 右值引用聲明符:聲明
S&& D; 將 D 聲明爲到 聲明說明符序列 所確定的類型 S 的右值引用。
右值引用
值引用可用於爲臨時對象延長生存期(注意,左值引用亦能延長臨時對象生存期,但不能通過左值引用修改它們):
#include <iostream>
#include <string>
int main()
{
std::string s1 = "Test";
// std::string&& r1 = s1; // 錯誤:不能綁定到左值
const std::string& r2 = s1 + s1; // okay:到 const 的左值引用延長生存期
// r2 += "Test"; // 錯誤:不能通過到 const 的引用修改
std::string&& r3 = s1 + s1; // okay:右值引用延長生存期
r3 += "Test"; // okay:能通過到非 const 的引用修改
std::cout << r3 << '\n';
}
懸垂引用
儘管引用一旦初始化,就始終指代一個有效的對象或函數,但有可能創建一個程序,被指代對象的生存期結束,但引用仍保持可訪問(懸垂(dangling))。訪問這種引用是未定義行爲。 一個常見例子是返回自動變量的引用的函數:
std::string& f()
{
std::string s = "Example";
return s; // 退出 s 的作用域:
// 調用其析構函數並解分配其存儲
}
std::string& r = f(); // 懸垂引用
std::cout << r; // 未定義行爲:從懸垂引用讀取
std::string s = f(); // 未定義行爲:從懸垂引用複製初始化
注意,右值引用和到 const 的左值引用能延長臨時對象的生存期.這是一種危險的做法。
若被指代對象被銷燬(例如通過顯式的析構函數調用),但存儲尚未被解分配,則到生存期外的對象的引用仍能以有限的方式使用,且當在同一存儲中重新創建對象時也可以變爲有效(細節見在生存期之外進行訪問)。