C++标准之(ravalue reference) 右值引用介绍


在C++中,右值引用(rvalue reference)是一种特殊的引用类型,用于引用即将被销毁的对象,即右值。右值引用通过类型后加两个`&&`符号来声明,如`int&&`。这种特性在C++11及以后的版本中引入,主要用于提高性能,特别是在移动语义(move semantics)和完美转发(perfect forwarding)中。

### 右值引用的基本概念

- **右值**:在C++中,右值通常是那些临时对象或者表达式的结果,它们没有持久的身份(即没有地址),在表达式求值结束后就会被销毁。

- **左值**:与之相对,左值是可以被取地址的表达式,它们有持久的身份,可以在多个表达式中被引用。

### 右值引用的用途

1. **移动语义**:允许对象在赋值或初始化时,通过“窃取”资源(如动态分配的内存)而不是复制它们,来优化性能。这通常通过成员函数的重载实现,一个接受左值引用,另一个接受右值引用(并通常将其标记为`noexcept`以鼓励移动)。

2. **完美转发**:允许模板函数或模板类将参数转发给另一个函数时,保持参数的左值或右值属性不变。这通过`std::forward`函数和模板参数包(template parameter packs)实现。

### 示例代码


#include <iostream>
#include <string>
#include <utility> // For std::move

class MyString {
public:
    MyString(const char* str) : data(new char[strlen(str) + 1]) {
        strcpy(data, str);
        std::cout << "Constructor called\n";
    }

    // Copy constructor
    MyString(const MyString& other) : data(new char[strlen(other.data) + 1]) {
        std::cout << "Copy constructor called\n";
        strcpy(data, other.data);
    }

    // Move constructor
    MyString(MyString&& other) noexcept : data(other.data) {
        other.data = nullptr;
        std::cout << "Move constructor called\n";
    }

    ~MyString() {
        delete[] data;
        std::cout << "Destructor called\n";
    }

    // Prevent copying
    MyString& operator=(const MyString&) = delete;

    // Move assignment
    MyString& operator=(MyString&& other) noexcept {
        if (this != &other) {
            delete[] data;
            data = other.data;
            other.data = nullptr;
        }
        return *this;
    }

    void print() const {
        std::cout << data << std::endl;
    }

private:
    char* data;
};

int main() {
    MyString s1("Hello");
    MyString s2 = std::move(s1); // 使用移动构造函数
    s1.print(); // 可能输出垃圾值,因为s1的资源已被移动
    s2.print(); // 输出 "Hello"

    return 0;
}

在这个例子中,`MyString`类展示了移动构造函数和移动赋值操作符的实现,以及如何使用`std::move`来显式地将左值转换为右值引用,从而触发移动操作。注意,虽然在这个例子中`s1.print()`可能输出垃圾值,但在实际使用中,移动后的对象应被视为处于未定义状态,不应再被使用。