右值引用 (C++11)

右值引用(Rvalue Reference)是 C++11 引入的关键特性,用于实现高效资源转移完美转发

1. 左值 vs 右值

左值 (Lvalue)
  • 特点:有持久状态、可取地址的表达式

  • 示例

    int a = 10;         // a 是左值
    std::string s = "hi"; // s 是左值
右值 (Rvalue)
  • 特点:临时对象、字面量、即将销毁的值

  • 示例

    42;                 // 字面量是右值
    std::string();      // 临时对象是右值
    a + b;              // 表达式结果是右值

2. 右值引用的语法

  • 符号&&(注意与通用引用区分)

  • 声明示例

    int&& rref = 42;           // 右值引用绑定到字面量
    std::string&& sref = get_temp_string(); // 绑定到临时对象

3. 核心用途

(1) 移动语义(Move Semantics)

问题场景:深拷贝临时对象效率低下

std::vector<int> create_big_vector(); // 返回临时对象

std::vector<int> v = create_big_vector(); 
// 传统拷贝:需要复制所有元素(低效)

解决方案:通过右值引用"窃取"资源

class Vector {
public:
    // 移动构造函数
    Vector(Vector&& other) noexcept 
        : data_(other.data_), size_(other.size_) {
        other.data_ = nullptr; // 使原对象处于可析构状态
    }
private:
    int* data_;
    size_t size_;
};

使用效果

Vector v1;
Vector v2 = std::move(v1); // 调用移动构造,仅转移指针
(2) 完美转发(Perfect Forwarding)

问题场景:模板函数参数传递时丢失左右值属性

template<typename T>
void wrapper(T arg) {
    func(arg); // 无论传入左值右值,arg都是左值
}

解决方案std::forward + 右值引用

template<typename T>
void wrapper(T&& arg) {          // 通用引用
    func(std::forward<T>(arg));  // 保持原始值类别
}

使用示例

wrapper(42);             // 转发右值
int x = 10;
wrapper(x);              // 转发左值

4. 关键函数与操作

工具作用
std::move()将左值强制转换为右值引用,启用移动语义
std::forward<T>()保持参数原始值类别(用于完美转发)
noexcept声明移动操作不抛异常(STL容器在重新分配时会优先使用noexcept移动操作)

5. 实际应用场景

场景1:优化容器操作
std::vector<std::string> merge(
    std::vector<std::string>&& a, 
    std::vector<std::string>&& b) {
    
    std::vector<std::string> result = std::move(a);
    result.insert(result.end(), 
                 std::make_move_iterator(b.begin()),
                 std::make_move_iterator(b.end()));
    return result; // 触发返回值优化(RVO)
}
场景2:实现资源管理类
class FileHandle {
public:
    FileHandle(FileHandle&& other) noexcept 
        : handle_(other.handle_) {
        other.handle_ = nullptr;
    }

    ~FileHandle() {
        if (handle_) close(handle_);
    }
private:
    FILE* handle_;
};

6. 注意事项

  1. 不要滥用std::move

    std::string s = "hello";
    std::string t = std::move(s); 
    // s现在处于有效但未定义状态(可能为空)
  2. 移动后对象应处于可析构状态

    class Resource {
        Resource(Resource&& other) {
            ptr_ = other.ptr_;
            other.ptr_ = nullptr; // 必须置空!
        }
        int* ptr_;
    };
  3. 区分通用引用和右值引用

    template<typename T>
    void foo(T&& param); // 通用引用(可能是左值或右值)
    
    void bar(int&& param); // 纯右值引用

为什么右值引用重要?

  • 性能提升:减少不必要的拷贝(特别是处理容器、字符串等资源密集型对象)

  • 实现资源所有权转移:如unique_ptr的核心机制

  • 支持完美转发:使模板函数能保持参数的原始值类别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值