C++ 中 & 符號雙重身份讓初學者困惑:
核心口訣:**「與類型在一起是引用,與變量在一起是取址」**。
int a = 10;
int& ref = a; // ref 是 a 的別名,編譯期綁定,運行期無額外存儲
ref = 20; // 修改 a 為 20
// 函式參數傳引用:避免拷貝、修改實參
void swap(int& x, int& y) { int t=x; x=y; y=t; }
// 返回引用:延長生命週期、鏈式調用
int& get_ref() { static int v; return v; }
get_ref() = 42; // 左值引用可作左值
關鍵規則:
std::reference_wrapper 等輔助)。sizeof(ref) == sizeof(int))。const 引用可綁定臨時對象/字面值/類型轉換結果:const int& r = 10; (延長臨時量生命週期)。int a = 10;
int* p = &a; // 取 a 的地址,生成指針
*p = 20; // 解引用修改 a
// 結構體成員取址
struct S { int x; };
S s; int* px = &s.x; // 成員地址
// 多級取址
int** pp = &p; // 取指針 p 的地址
關鍵規則:
T* (指向對象類型的指針)。&&a 非法,但 &*&a 合法 (等價 &a)。| 維度 | 引用 (& 在聲明中) | 取地址 (& 在表達式中) |
|---|---|---|
| 出現位置 | 類型聲明中,變量名前 | 表達式中,變量/對象前 |
| 語法角色 | 宣告符 (Declarator) | 一元運算符 (Operator) |
| 結果類型 | 引用類型 T& | 指針類型 T* |
| 語義 | 建立別名綁定 | 獲取記憶體地址 |
| 可重新綁定 | 否 | 指針可指向新對象 |
| 適用對象 | 左值、const 引用可綁右值 | 僅左值 |
| 典型用途 | 函式參數/返回、範圍 for、別名 | 指針初始化、C API 互操作、觀察者模式 |
int x = 1;
int& r1 = x; // (1) 引用宣告:r1 綁定 x
int* p1 = &x; // (2) 取地址:p1 指向 x
int& r2 = *p1; // (3) 引用宣告:r2 綁定 *p1 (即 x)
int* p2 = &r1; // (4) 取地址:對引用取址 → 取被引用對象地址 → p2 指向 x
int&& rv = 10; // (5) 右值引用宣告 (C++11)
int* p3 = &rv; // (6) 取地址:右值引用也是左值表達式,可取址
// 錯誤示例
int* p4 = &10; // 錯誤:字面值無地址
int& r3 = 10; // 錯誤:非 const 引用不可綁定右值
const int& r4 = 10; // 正確:const 引用延長臨時量生命週期
C++11 引入 && (右值引用宣告符),支援移動語義與完美轉發:
void process(int&& x) { /* 接管臨時對象資源 */ }
process(42); // 42 是右值,綁定到 int&&
int a = 10;
process(std::move(a)); // 將左值轉為右值引用
辨析:&& 在聲明中是右值引用宣告符;在模板參數推導/轉發引用中 (T&&) 是**通用引用**,可綁定左值/右值,需配合 std::forward。
sizeof(ref) 得到指針大小,無法算術運算,無法置空。for (auto& x : v) x *= 2;;只讀用 const auto& 避免拷貝。vector 擴容、map/set 重平衡、string SSO 狀態變化,均可能使現有引用/指針/迭代器失效。& 的雙重身份是 C++ 兼容 C 語法並引入引用機制的歷史遺產。牢記 **「類型邊是引用,變量邊是取址」**,結合左值/右值、const/非 const、聲明/表達式上下文,即可輕鬆辨析。現代 C++ 更應善用引用簡化代碼、避免拷貝、表達所有權語義,將指針保留給底層互操作與性能極致場景。