右值引用的出现导致了移动语义的产生,让C++的性能产生了提升,这个提升来源与对Copy的减少。
右值引用有什么用呢?
它的作用是调用临时变量,虽然const引用也能调用临时变量,但const引用也能调用栈变量和堆变量,const引用作为形参的时候,我们是分辨不出来是那种变量的引用的,所以const引用它不能导致移动语义的产生;
移动语义是怎么减少Copy的?
我们先思考问题,当我们用一个临时变量去初始化某一个类的时候,我们会经历那些步骤:
看下面的代码:
#include<iostream>
class String {
public:
String(const char* ptr) {
std::cout << "Create" << std::endl;
this->size = strlen(ptr);
this->ptr = new char[this->size];
memcpy(this->ptr, ptr, this->size);
}
String(const String& str) {
std::cout << "Copy" << std::endl;
this->size = strlen(str.ptr);
this->ptr = new char[this->size];
memcpy(this->ptr, str.ptr, this->size);
}
~String() {
std::cout << "Destory" << std::endl;
delete ptr;
}
private:
int size;
char* ptr;
};
class Test {
public:
Test(const String& Str)
:m_Str(Str) {}
private:
String m_Str;
};
int fun(int&& a) {
a = 1;
return a;
}
int main() {
Test test("LHM");
}
运行结果:
Create
Copy
Destory
Destory
我们创建了两次String,向堆内存申请了两次内存;
1:“LHM”->String类型要生成一个临时变量
2:临时变量传给test中的变量进行Copy
这里我们想,能否让test直接指向临时变量,而不用进行copy,这样做其实没有风险,因为在这个临时变量出现之前,是没有被任何变量依赖的。
这里我们就可以用右值引用了,思路是直接让Test中的ptr等于临时变量中的ptr,然后将临时变量中的ptr指空【有一点像打劫】;
看以下代码:
#include<iostream>
class String {
public:
String(const char* ptr) {
std::cout << "Create" << std::endl;
this->size = strlen(ptr);
this->ptr = new char[this->size];
memcpy(this->ptr, ptr, this->size);
}
String(const String& str) {
std::cout << "Copy" << std::endl;
this->size = strlen(str.ptr);
this->ptr = new char[this->size];
memcpy(this->ptr, str.ptr, this->size);
}
String(String&& str) {
std::cout << "Move" << std::endl;
this->size = str.size;
this->ptr = str.ptr;
str.ptr = nullptr;
}
~String() {
std::cout << "Destory" << std::endl;
delete ptr;
}
private:
int size;
char* ptr;
};
class Test {
public:
Test(const String& Str)
:m_Str(Str) {}
Test(String&& Str)
:m_Str((String&&)Str) {}
private:
String m_Str;
};
int main() {
Test test("LHM");
}
运行结果:
Create
Move
Destory
Destory
只new了一次