std::move

std::move

看功能先看源码:

namespace std {

template <typename T>
typename std::remove_reference<T>::type&& move(T&& arg) noexcept {
    return static_cast<typename std::remove_reference<T>::type&&>(arg);
}

可以看到其返回值进行了一个static的强制类型转化,并且又用到了std::remove_reference,那再看看这个源码是什么:

template <typename T>
struct remove_reference {
    using type = T;
};

template <typename T>
struct remove_reference<T&> {
    using type = T;
};

template <typename T>
struct remove_reference<T&&> {
    using type = T;
};

template <typename T>
using remove_reference_t = typename remove_reference<T>::type;

从这个代码可以看出,无论给remov_reference传入什么类型(即T类型,T的右值引用,T的左值引用),都会定义一个别名为type的T类型,作用显而易见就是去掉引用(&&或&),意义在于移除类型的引用修饰,返回对应的非引用类型。
回到std::move上,他可以使move的返回类型为std::remove_reference<_TP>::type&&,简化来看就是T的右值引用,通过代码内部的static_cast转换而来。

于是我们可以简化一下std::move函数

template <typename T>
typename T&& move(T&& arg){
	return T&&(arg);
}

那么了解了源码之后,我就碰到下面的问题:
假设A,B是两个数组,且数组元素都是可移动类型的,例如std::vector;
那么对于

case1:
A = std::move(B);
cout << B[1] << endl;

case2:
std::move(B);
cout << B[1] << endl;

这两种情况执行cout这一句会报错吗?

先看case2,这是一个临时表达式,返回的是一个右值引用,表示B可以被移动。这条语句本身并不会对B造成实际影响,它只是将B转换为右值引用,这条语句本身不会影响数组B。因此,访问B[1]应该能够正常编译和执行。
那么看case1,多了个A = ,则会触发调用移动赋值操作符,将数组B的内容移动到数组A中,对于移动赋值操作,可以简单康康其源码:

class MyClass {
public:
    // 构造函数
    MyClass(int val) : data(new int(val)) {}

    // 移动赋值操作符
    MyClass& operator=(MyClass&& other) noexcept {
        if (this != &other) {  // 检查是否为同一对象
            delete data;  // 释放当前对象的资源
            data = other.data;  // 移动资源所有权
            other.data = nullptr;  // 设置原对象为无效状态
        }
        return *this;
    }

private:
    int* data;
};

其意义在于:
构造函数 MyClass(int val):这是类的构造函数,它接受一个整数值 val,并在堆上分配一个 int 类型的资源,将 val 的值存储在这个资源中。
移动赋值操作符 operator=(MyClass&& other):这是移动赋值操作符,用于将一个右值引用的 MyClass 对象的资源移动给当前对象。在这个操作符的实现中:
1、首先,它检查当前对象是否与右值引用 other 是同一个对象,以避免不必要的操作。
2、然后,它释放当前对象的资源,通过 delete data; 来释放之前分配的资源,以确保当前对象在获得新资源的同时,不再持有旧资源。通过释放旧资源,可以防止内存泄漏,并确保资源的正确管理。
3、接着,它将 other 的资源指针赋值给当前对象的 data 成员,即移动了资源的所有权。
4、最后,它将 other 的资源指针设置为 nullptr,将原对象置于无效状态,以避免 other 在析构时释放已经移动的资源。

从这个移动赋值操作可以看出,意味着B的内容会被转移给A,并且B的内容会被置为移动后的有效但未指定的状态。在执行完这条语句后,B应该是不再持有有效的数据。

总而言之,std::move本身只会进行强制类型转换,变成右值,如果没有上下文的影响,其可以照常像右值一样使用,如果进行了将其对其他具名变量赋值操作之后,其实也就是触发了所谓的“移动语义”,资源就会转移到像上述A中,本身资源状态可能就会变成无效的了。

问题及解答来源:面试经验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值