右值引用使用说明

形参

比如一个函数foo(Type&& par)

  • 写函数的人要保证在函数里面"挪用了par资源",如果只是简单的引用,就写成(Type& par)就行,一定不要为了装逼非要写成右值传参。如果非要这么写,只有一种情况:

由于左值引用只能针对已经存在的对象,对于没有持久化地址、通常是临时对象、字面量、或在表达式中求值之后不再需要的对象无法使用,右值引用就是做这个事情的。

  • 由于实参大部分是临时对象,所以函数里面基本都要出现Type other=move(par), 目的是为了调用Type的移动构造函数,把内存资源转移到一个正常的对象。这里切记,不能写成Type&& other=move(par), 这样不会调用任何移动构造函数,好好理解
  • 或者函数里面要出现static_cast<Type&&>(par)这种字眼,目的是转给一个形参是右值引用的第三方函数。

注意:

  1. foo(tmp),在调用阶段不会使用移动构造函数,类似于左值引用,本质也是传一个指针,只有在函数里面利用move(tmp)(时刻记住,一旦给一个右值起了个名字就会变成左值)去初始化和赋值其他变量时候才会使用移动构造函数。
  2. move的本质是就是调用static_cast<type&&>(par), 由于右值没有名字所以不存在数据类型一说,根据move的实现原理可以看出右值的本质数据类型是type&&. 这个观念也要清楚。
//传入右值
vec_bc.push_back(BaseClass("b3", 1));
则,需要执行以下步骤
1. 调用构造函数,构造出右值A
2. 调用 move 构造函数,copy 数据到 vector 的数据空间 的对象 B
3. 在参数声明周期结束后,调用A 的析构函数,
//传入左值
{  
    BaseClass b4("b4", 1);
    vec_bc.push_back(b4);
}
则,需要执行以下步骤
1. 调用构造函数,构造出右值A
2. 调用 copy 构造函数,copy 数据到 vector 的数据空间 的对象 B
3. 在参数声明周期结束后,调用A 的析构函数,

可以看到唯一的区别就是,一个调用了移动构造函数(这个性能会好很多),一个调用了copy构造函数,对于BaseClass而言,基本都是如下实现, 其实核心就是交接堆区域的内存,注意移动构造函数一旦调用就必须让资源句柄置为空,否则会被析构函数析构掉,逻辑就是资源已被转移就不要再析构了

#include <iostream>
#include <cstring>

class MyClass {
private:
    char* data;

public:
    // 默认构造函数
    MyClass(const char* str = "") {
        if (str) {
            data = new char[strlen(str) + 1];
            strcpy(data, str);
        } else {
            data = nullptr;
        }
        std::cout << "Constructor: " << data << std::endl;
    }

    // 移动构造函数
    MyClass(MyClass&& other) noexcept : data(other.data) {
        other.data = nullptr;  // 把 `other` 的资源置为空,防止析构时释放数据
        std::cout << "Move Constructor: " << data << std::endl;
    }

    // 析构函数
    ~MyClass() {
        if (data) {
            std::cout << "Destructor: " << data << std::endl;
            delete[] data;  // 释放分配的内存
        }
    }

    // 禁用拷贝构造函数,避免不必要的资源复制
    MyClass(const MyClass& other) = delete;

    // 禁用拷贝赋值操作符
    MyClass& operator=(const MyClass& other) = delete;

    // 显示数据
    void show() const {
        std::cout << "Data: " << (data ? data : "null") << std::endl;
    }
};

int main() {
    MyClass obj1("Hello, world!");
    obj1.show();

    MyClass obj2 = std::move(obj1);  // 触发移动构造
    obj2.show();
    obj1.show();  // obj1的数据已经被移动,变为nullptr

    return 0;
}

返回值

比如一个函数的返回值是Type&& foo()这就代表了返回的是一个右值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值