C++11 引入的右值引用與移動語義是現代 C++ 性能優化的核心特性。本文系統解析左值/右值區別、引用類型演進、移動語義實現機制,並通過 MyString 類完整示例展示如何消除不必要的拷貝,大幅提升資源管理效率。
int a)。本質是內存位置(Location)。3、a+b)。本質是數據值(Read)。經典判斷:能出現在賦值號左邊的是左值,只能出現在右邊的是右值。
| 引用類型 | 語法 | 綁定對象 | 典型用途 |
|---|---|---|---|
| 非常量左值引用 | T& | 非常量左值 | 修改對象 |
| 常量左值引用 | const T& | 左值、右值均可 | 只讀參數傳遞 |
| 右值引用 | T&& | 右值(臨時對象) | 移動語義、完美轉發 |
void process(int& i) { cout << "LValue: " << i << endl; }
void process(int&& i) { cout << "RValue: " << i << endl; }
int main() {
int a = 0;
process(a); // 輸出 LValue
process(1); // 輸出 RValue
process(std::move(a)); // 輸出 RValue
}
關鍵規則:有名字的右值引用在函數內部是左值。
void forward(int&& i) {
process(i); // i 有名字 → 視為左值 → 調用 process(int&)
}
int main() {
forward(2); // 輸出 LValue processed: 2
}
class MyString {
char* _data; size_t _len;
// 拷貝構造
MyString(const MyString& str) {
_len = str._len;
_data = new char[_len+1];
memcpy(_data, str._data, _len);
cout << "Copy Ctor" << endl;
}
// 拷貝賦值
MyString& operator=(const MyString& str) { ... }
};
輸出:Copy Assignment... Copy Constructor... —— 每次操作都伴隨內存申請、拷貝、釋放。
class MyString {
char* _data; size_t _len;
// 移動構造
MyString(MyString&& str) noexcept {
_len = str._len;
_data = str._data; // 直接接管指針
str._len = 0;
str._data = nullptr; // 來源置空,防止析構釋放
cout << "Move Ctor" << endl;
}
// 移動賦值
MyString& operator=(MyString&& str) noexcept {
if (this != &str) {
delete[] _data;
_len = str._len;
_data = str._data;
str._len = 0;
str._data = nullptr;
}
cout << "Move Assign" << endl;
return *this;
}
};
輸出:Move Assignment... Move Constructor... —— 僅指針轉移,零內存拷貝。
int a = 10;
process(a); // LValue
process(std::move(a)); // RValue —— 強制啟用移動語義
本質:static_cast<T&&>(arg),編譯期類型轉換,零運行開銷。
// 傳統 swap(3 次拷貝)
template <class T> void swap(T& a, T& b) {
T tmp(a); a = b; b = tmp;
}
// 移動版 swap(3 次移動,無拷貝)
template <class T> void swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
場景:包裝器函數需將參數原封不動(含左/右值、const 屬性)傳給目標函數。
// 傳統需 2^n 個重載
template <typename T> void forward(const T& val) { process(val); }
template <typename T> void forward(T& val) { process(val); }
// C++11 單一模板搞定
template <typename T> void forward(T&& val) { process(std::forward<T>(val)); }
核心規則:右值實參推導為右值引用,左值實參推導為左值引用(引用摺疊)。
noexcept,助優化容器重分配std::move 主動轉移std::forward 實現完美轉發文末附帶完整測試程式,涵蓋返回值優化 (RVO)、std::move 強制移動、賦值與構造的各種組合場景,輸出詳細構造/賦值日誌,助你直觀掌握編譯器決策邏輯。