您的位置:首页 > 编程语言 > C语言/C++

C++ std::move原理&右值引用存在的必要性

2017-05-10 22:43 134 查看
在学习C++的过程中一直搞不懂为什么要存在右值引用,将左值引用变为右值引用

个人认为就是减少拷贝构造,赋值重载过程内存开辟拷贝的次数,提高速度

我们现在看一段代码:

#include <iostream>
#include <cstring>
using namespace std;

class Student{

friend class Teacher;
private:

char * pStart;
int length;

public:

Student(char* p = nullptr){
cout << "contructer" << endl;
if(p == nullptr){
this->pStart = nullptr;
this->length = 0;
}else{
this->length = strlen(p) +1;
this->pStart = new char[this->length];
strcpy(this->pStart,p);
}
}

Student(const Student& stu){
cout << "copy constructer" << endl;
this->length = stu.length;
this->pStart = new char[this->length];
strcpy(this->pStart,stu.pStart);

}

void operator=(const Student& stu){

cout << "== coonstructer"<< endl;
if(this->pStart != nullptr){
delete[] this->pStart;
}

this->length = stu.length;
this->pStart = new char[this->length];
strcpy(this->pStart,stu.pStart);

}

~Student(){
cout << "delete" << endl;
if(this->pStart != nullptr){
delete[] this->pStart;
this->pStart = nullptr;
}

}

friend ostream& operator<<(ostream& cout,const Student&stu){
cout << "value = " << stu.pStart << endl;
return cout;
}

};
Student funcTest(){

Student stu("Beijing");
return stu;


Studnt类里面有个字符串成员变量,我们每次在进行拷贝 赋值的时候都要进行开辟内存,拷贝数据的过程。

funcTest()函数会返回Student对象。当我们调用stu = funcTest()的时候:

1:Student stu("Beijing")会调用一次构造函数

2:由于函数执行完会释放栈上的内存,所以stu会被析构,但是要将stu作为返回值返回,编译器会创建一个临时对象(通过拷贝stu实现),这个临时对象不再内存中

      就是我们常说的右值,可以理解为在CPU的寄存器中。左值 很粗的理解就是在内种中特定存在的.

3:stu会对临时对象(右值)进行拷贝构造

总结:stu = funcTest()一共会调用1次构造,1次拷贝,1次右值重载

看函数调用结果:

void main(){

Student stu3("beijing");
stu3 = funcTest();
cin.get();

}



下面考虑一个问题这个我们知道函数funTest()返回Student其实是一个临时对象,这个临时对象用一次就被析构了,赋值重载过程中能不能将指针指向临时对象的内存,减少内存开辟拷贝的过程。

下面我们就要引出右值引用的代码了:

Teacher(Student&& stuparam){
cout << "右值引用"<< endl;
stu.length = stuparam.length;
stu.pStart = stuparam.pStart;
stuparam.pStart= nullptr;
}

我们看到将指针指向临时对象的内存就可以不用开辟内存了,但是为什么要将临时对象的pStart变成nullptr?因为这个临时对象会立刻被析构,如果不变成nullptr,我们再次访问pStart的时候,指向的内存因为析构了变成垃圾值了。具体看代码:

Student stu3("beijing");
stu3 = funcTest();
cout << "==============================" << endl;


执行结果:



如果右值引用的代码变成这样:

void operator=(Student&& stu2){
cout << "右值拷贝"<< endl;
if(this->pStart != nullptr){
delete[] this->pStart;
}
this->pStart = stu2.pStart;
this->length = stu2.length;
//stu2.pStart = nullptr;

}

执行结果:



下面在通过一段代码来巩固一下右值引用的作用到底有多大

class Teacher{

private:
Student stu;
public:
Teacher(const Student& stuparam){
cout << "左值引用" << endl;
stu = stuparam;
}

Teacher(Student&& stuparam){
cout << "右值引用"<< endl;
stu.length = stuparam.length;
stu.pStart = stuparam.pStart;
stuparam.pStart= nullptr;
}

void test(){
cout << stu << endl;
}

};

void main(){

//Sdudent("12222")临时对象也就是右值
Teacher t(Student("12222"));
t.test();

cin.get();

}


执行结果如图:



void main(){

Student stu2("Nanjing By Zhongqi.Shao");
//Sdudent("12222")临时对象也就是右值
Teacher t(stu2);
t.test();

cin.get();

}



void main(){

Student stu2("Nanjing By Zhongqi.Shao");
//Sdudent("12222")临时对象也就是右值
Teacher t(std::move(stu2));
t.test();

cin.get();

}

结果如下:



到这你就明白为什么要std::move(leftValue)了吧,以及明白了右值引用到底做了什么了 哈哈哈 。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: