参考一篇不错的博文
核心思想:
临时对象被使用完之后会被立即析构,在析构函数中free掉申请的内存资源。
如果能够直接使用临时对象已经申请的资源,并在其析构函数中取消对资源的释放,这样既能节省资源,又能节省资源申请和释放的时间。 这正是定义移动语义的目的。
简单来说,类的构造函数、使用左值引用的构造函数、operator=重载函数等,会申请新的内存,复制数据;而使用右值引用的这些函数中,则直接使用原有的内存,并保证原有内存不被释放,这样就节省了一部分时间,提高了swap等函数的效率。
在使用自定义类时,用户可以根据需求选择左值引用还是右值引用,而选择右值引用带来的性能提升则取决于类函数的写法了。例如,使用vector的左值引用与右值引用几乎没有差别,而下面的例子使用右引则快了很多。
std::move函数就是将左引转换为右引。
上代码:
#include <iostream>
#include <vector>
using namespace std;
class MyString
{
public:
MyString()
{
m_data = NULL;
m_len = 0;
}
MyString(const char* s)
{
m_len = strlen(s);
init_data(s);
cout << "构造函数" << s << endl;
}
MyString(const MyString& str)
{
m_len = str.m_len;
init_data(str.m_data);
cout << "拷贝构造函数" << str.m_data << endl;
}
MyString(MyString&& str)
{
cout << "移动构造函数" << str.m_data << endl;
m_len = str.m_len;
m_data = str.m_data;
str.m_len = 0;
str.m_data = NULL;// 防止在析构函数中将内存释放掉
}
MyString& operator=(const MyString& str)
{
if (this != &str) {
this->m_len = str.m_len;
init_data(str.m_data);
}
cout << "等号操作符重载" << str.m_data << endl;
return *this;
}
MyString& operator=(MyString&& str)
{
cout << "移动等号操作符重载" << str.m_data << endl;
if (this != &str) {
this->m_len = str.m_len;
this->m_data = str.m_data;
str.m_len = 0;
str.m_data = NULL;// 防止在析构函数中将内存释放掉
}
return *this;
}
~MyString()
{
if (m_data != NULL) {
cout << "析构函数" << endl;
free(m_data);
}
}
private:
void init_data(const char* s)
{
m_data = new char[m_len + 1];
memcpy(m_data, s, m_len);
m_data[m_len] = '\0';
}
char* m_data;
size_t m_len;
};
namespace MyT {
template <class T>
void swapWithMove(T& a, T& b)
{
T tmp(std::move(a));// move a to tmp
a = std::move(b);// move b to a
b = std::move(tmp);//move tmp to b
}
template<class T>
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
}
void test()
{
MyString a("hello");
MyString b("world");
int n = 200;
clock_t t0 = clock();
for (int i = 0; i < n; i++)
{
MyT::swap<MyString>(a, b);
}
clock_t t1 = clock();
for (int i = 0; i < n; i++)
{
MyT::swapWithMove<MyString>(a, b);
}
cout << t1 - t0 << endl;
cout << clock() - t1 << endl;
}
int main()
{
test();
return 0;
}
运行结果:
可以看到使用右引的swap函数要比使用左引快了1/6。这是由于使用左引的构造函数、operator=函数中调用了init_data(),进行了字符串的拷贝,而右引时省去了这一操作。