目录
在了解右值引用之前我们先来了解一下 什么是左值和右值
左值 :就是表达式结束还存在的长久对象 理解上是有确定的存储地址
右值 :就是表达式结束就不存在的临时对象(通常是表达式的计算结果,如常量、临时对象、表达式求值的结果)
这里就不得不提到我们所熟知的 i++ 和 ++i 了
我们所熟悉的 i++是返回++之前的值 ++i是返回++之后的值
&i++ //error 这里出现的错误是 表达式必须是左值
i++ // 这里是将我们i的值放入到一个临时变量里 然后将临时变量进行自增并返回 所以‘是一个右值
++i // 自增并返回自己 左值
我们先来看一下普通引用怎么定义 (这里的我们常见的引用是左值引用)
这里是关于int变量的引用 以及他们sizeof的大小:
右值引用
下面以我们关于右值引用的定义
int x=10;
int&& rref = 42; // 定义一个右值引用
int&& result = x + 5; // 表达式 x + 5 是一个右值
那么这个右值引用有什么作用呢???
通过右值引用,我们可以标识出我们希望对右值进行特殊处理,例如移动语义。综合起来,将右值引用绑定到右值意味着我们可以通过引用来访问和操作临时生成的值,同时也可以利用这个特性来实现移动语义,从而在一些情况下避免不必要的数据拷贝
下面我们来看一下具体情况
#include <iostream>
#include <stdlib.h>
using namespace std;
class MyString {
public:
MyString(const char* str) {
size = strlen(str);
data = new char[size + 1];
strcpy_s(data, size + 1, str);
}
// 移动构造函数,使用右值引用接受另一个 MyString 对象的资源所有权
MyString(MyString&& other) : data(other.data), size(other.size) {
other.data = nullptr; // 赋空源对象的指针防止误用
other.size = 0;
}
~MyString() {
delete[] data;//因为是new[]所以必须用delete[]
}
const char* getData() const {
return data;
}
private:
char* data;
size_t size;
};
int main() {
MyString a = "Hello, World!";
MyString b = move(a); // 使用 std::move() 标记 a 为右值,调用移动构造函数
cout << "b: " << b.getData() << endl;
return 0;
}
我们来看一下结果:
我们可以看到a 的使用权限已经被释放
右值引用的移动构造函数和移动语义的主要优势在于,它们能够在不进行资源的深拷贝的情况下,将资源的所有权从一个对象转移到另一个对象。移动构造函数通常用于转移资源所有权,同时将源对象的状态置于有效但未定义的状态,从而避免了不必要的资源拷贝。