简介
第一次接触c++move操作就懵逼了,一直想探个究竟,但是右值以及右值引用思考了好长时间,就是不得要领,今天终于有所收获,写下第一篇博客,一方面为了帮助一些刚入门的朋友,另一方面也是帮助自己今后复习。
右值 左值 右值引用 左值引用 含义
左值是一个持久的量,右值是一个短暂的量。那怎么算持久怎么算短暂呢?取决于我的代码里有没有一个变量来保存他。举个例子:
int i = 5;
string s1(“ppap”);
都可以完成取地址的操作的操作 &i,&si;
那么定义一个左值引用,就是给这些地址起一个其他的名字罢了,地址是不会发生变化的,也就是说左值引用的本质其实还是指针:
int &k = i;
string & s2 = s1;
右值就不一样了,右值是一个即将消亡的值,那么怎么算即将消亡?就是没有人记得他了:
string (“ppap”);
这样一个语句的的确确在这个函数栈中构造了这么一个空间,只不过可惜的是他是没有名字的!如果我在这个语句段中执行赋值或者拷贝,那么他起到了临时变量的作用:
string s1 = string(“ppap”);
但是一旦离开这一段语句,我就再也找不到这段空间的地址了,也就是一定意义上的消亡,但是这个消亡指的是没有人记得他了,它自身真正的消失是发生在函数栈清除;
那么理解了右值就可以说明什么是右值引用了。右值引用的含义就是,我想记下这个临时的,快要消亡的,马上就没得人记得他的名字(地址)。
那么换句话说:
const int & i = 1;
int && i = 1;
其实在某些意义上是等价的(不是完全等价)
右值引用的意义以及move
关于右值引用的意义,我的理解是:告诉编译器,这个变量我不要了,在执行赋值、拷贝构造等操作的时候,调用我提供的移动构造函数!
而move的底层其实就是一个静态强制转换,无论你是什么类型,一律变成右值引用类型,去强制匹配提供的右值引用形参的函数(用于实现接管资源)。
综上所述,右值引用在我看来有两种作用:
1:获取一个匿名临时变量的地址。
2:通过move强制转换告诉编译器,这个变量我不需要了,请帮我调用形参为右值引用的函数,来接管这份资源。
下面给一个例子在这里插入代码片
class str {
public:
friend ostream& operator <<(ostream& out, const str& p);
str() :data(nullptr), len(0) {}
//构造函数
str(const char* p) {
len = strlen(p);
data = new char[len + 1];
strcpy(data, p);
cout << "执行了char * 的构造函数" << endl;
}
str(const str& p) {
len = p.len;
data = new char[len+1];
strcpy(data, p.data);
cout << "执行了 拷贝构造函数" << endl;
}
str& operator = (const str & p){
if (this == &p) return *this;
delete []data;
len = p.len;
data = new char[len + 1];
strcpy(data, p.data);
cout << "执行了拷贝赋值" << endl;
return *this;
}
str(str&& p) {
if (this != &p) {
len = p.len;
data = p.data;
p.data = nullptr;
p.len = 0;
cout << "执行了移动构造" << endl;
}
~str() {
delete[]data;
cout << "执行了析构" << endl;
}
private:
char * data;
int len;
};
ostream& operator<<(ostream& out, const str& p) {
out << p.data;
return out;
}
int main()
{
str s1("ppppp");
str s3 = s1;
str s2(std::move(s1));
}
结果为: