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;
}
};
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(){
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)了吧,以及明白了右值引用到底做了什么了 哈哈哈 。。。。
个人认为就是减少拷贝构造,赋值重载过程内存开辟拷贝的次数,提高速度
我们现在看一段代码:
#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)了吧,以及明白了右值引用到底做了什么了 哈哈哈 。。。。
相关文章推荐
- Item 24: 区分右值引用和universal引用
- C++11 --右值引用(Rvalue Reference) Part1
- Item 25: 对右值引用使用std::move,对universal引用则使用std::forward
- 深刻理解引用、const引用、右值引用的本质
- C++ 11 右值引用的理解
- C++ 11右值引用
- C++11标准新特性:右值引用与转移语义
- c++11之左值引用和右值引用
- 【翻译】VC10中的C++0x新特性:右值引用(rvalue references) (1)
- C++11右值引用
- 详解C++右值引用
- 【翻译】VC10中的C++0x新特性:右值引用(rvalue references) (3)
- 类成员变量中存在引用,const,和指针类型时需要注意的事项
- 《C++0x漫谈》系列之:右值引用或“move语意与完美转发”(下)
- C++0x尝鲜:右值引用
- c++11 shared_ptr & unique_ptr & move semantics(右值引用) & lock_guard & final 和 override 关键字
- C++11 左值、右值与右值引用
- C++11:右值引用和转移赋值
- C++11 右值引用和转移语义
- C++11特性--右值引用,移动语义,强制移动move()