说到C++11新增的move,得先说一下左值和右值。
比如int a = 1; int b = a;
我们说在b=a
中,a是左值,因为它有名字,在之后还可以访问到;
而int a = 1; int b = a + c;
这里得a+c
就是右值,它是一个临时变量,没有名字,所以之后无法对它进行访问。
对于移动构造函数(move constructor)
#include <cstring>
#include <algorithm>
class string
{
char* data;
public:
string(const char* p)
{
size_t size = std::strlen(p) + 1;
data = new char[size];
std::memcpy(data, p, size);
}
~string()
{
delete[] data;
}
string(const string& that)
{
size_t size = std::strlen(that.data) + 1;
data = new char[size];
std::memcpy(data, that.data, size);
}
上述例程中的拷贝构造函数(copy constructor)是一个深拷贝,我们在堆上开辟新的内存空间,然后将that的数据一一拷贝过来。
对于左值,使用拷贝构造函数是必须的。比如string a(x);
,因为我们之后还可能继续访问x
对于右值,比如string b(x+y);
或者string c(some_function_returning_a_string());
,x+y
和some_function_returning_a_string()
这样的临时变量在之后不能被访问到,在下一个语句时就会被析构掉,那为何不好好利用起来呢?因为对于右值,我们不直接深拷贝堆数据,而是直接拷贝这个临时变量的数据指针。具体如下
string(string&& that) // string&& is an rvalue reference to a string
{
data = that.data;
that.data = nullptr;
}
因为这并不是拷贝,所以称为移动构造(move constructor)。