---
# System prepended metadata

title: '技術｜C++｜C++ rvalue 和 std::move'

---

# 技術｜C++ ｜C++ rvalue 和 std::move

## lvalue
- 具名的、可定位的對象
```c++=
int x = 5; // x 是 lvalue，因為它是一個具名的變量
x = 10;    // 可以對 x 賦值，修改它的值
```
- lvalue reference: 可以綁定到一個lvalue
```c++=
int a = 5;
int& ref = a;  // ref 是 a 的 lvalue 引用
```
## rvalue
臨時的、不可取址的`值`
```c++=
int y = 5;  // 5 是一個 rvalue，因為它是臨時的常量，無法通過地址修改
y = x + 3;  // (x + 3) 是 rvalue，它的結果不再持續存在
```
- rvalue reference: 允許綁定到rvalue
```c++=
int&& temp = 10;  // temp 是一個 rvalue 引用
```
## 移動語意
- 為了減少不必要的拷貝操作，C++11 引入了移動語意，讓我們可以移動資源而不是拷貝它們。
- 為了支持移動語意，你需要在類中實現`移動構造函數`和`移動賦值運算符`
    ```c++=
    class MyClass {
        int* data;
        int size;  // 需要記住 size，方便複製操作
    public:
        // 構造函數
        MyClass(int size) : size(size) {
            data = new int[size];  // 分配內存
        }

        // 複製構造函數 : 深拷貝
        MyClass(const MyClass& other) : size(other.size) {
            data = new int[other.size];
            for (int i = 0; i < size; ++i) {
                data[i] = other.data[i];
            }
        }

        // 複製賦值運算符 : 深拷貝
        MyClass& operator=(const MyClass& other) {
            if (this != &other) {
                // 釋放現有的內存
                delete[] data;

                // 分配新內存並進行深拷貝
                size = other.size;
                data = new int[size];
                for (int i = 0; i < size; ++i) {
                    data[i] = other.data[i];
                }
            }
            return *this;
        }

        // 移動構造函數 : 避免 copy
        MyClass(MyClass&& other) noexcept : data(other.data), size(other.size) {
            other.data = nullptr;
            other.size = 0;
        }

        // 移動賦值運算符 : 避免 copy
        MyClass& operator=(MyClass&& other) noexcept {
            if (this != &other) {
                // 釋放現有的內存
                delete[] data;

                // 移動數據
                data = other.data;
                size = other.size;
                other.data = nullptr;
                other.size = 0;
            }
            return *this;
        }

        // 析構函數
        ~MyClass() {
            delete[] data;  // 釋放資源
        }
    };
    ```
- 移動語意主要應用於：
    - 容器類別（如 vector、string）：當容器中元素是臨時對象時，移動語意可避免不必要的深拷貝。
    - 函數返回值優化（RVO）：通過移動語意返回臨時對象，直接轉移資源。
    - 資源管理：如動態內存、文件句柄、網絡連接等資源，通過移動語意可以避免資源的重複分配和釋放。
- 當呼叫移動函數 `std::move` 後
    - caller 不應該再繼續使用該物件
    - 實作應該把 rhs 設定成即使 caller 呼叫 destructor 也不會有問題的狀態 (如設成 nullptr)
## std::move 
- 在 C++ 中，默認情況下變量是 lvalue
- `移動語意只會作用於 rvalue（臨時對象)`，std::move 可以顯式地將該對象轉換為 rvalue reference。
- 使用者透過是否呼叫 `std::move()` 決定要帶入左值或右值，以呼叫正確的`複製 or 移動函數`
    ```c++= 
    int main() {
        MyClass obj1(10);
        
        // 複製構造
        MyClass obj2 = obj1;

        // 複製賦值
        obj2 = obj1
        
        // 移動構造
        MyClass obj3 = std::move(obj1);

        // 移動賦值
        obj3 = std::move(obj1);
    }
    ```
- 以 STL 為例，他實作兩個版本，使用 move 可以帶來效能提升
    ```c++=
    vec.push_back(str1);            // 傳統方法，copy
    vec.push_back(std::move(str1)); // 使用移動以提升性能
    ```
- [一文讀懂C++右值引用和std::move](https://zhuanlan.zhihu.com/p/335994370)
- [移動語意 std::move() 的用途與原則](https://charlottehong.blogspot.com/2017/03/stdmove.html)