# C++ 的移动语义与右值引用

Gaze

# 移动语义

# 为何需要移动语义

假设有如下代码:

vector<string> vstr;// build up a vector of 20000 strings,each of 1000 characters
vector<string> vstr_copy1(vstr);

为了初始化 vstr_copy1 先调用 vector 的复制构造函数,使用 new 给 20000 个 string 对象分配内存,而每个 string 对象又调用 string 的复制构造函数,为 1000 个字符分配内存。这很浪费时间,但如果 vstr 与 vstr_copy1 都需要使用,这很难避免。

可有时候这样不太妥当,例如 vstr 不再被使用时。例如如下定义的函数:

vector<string> allcaps(const vector<string> & vs)
{
    vector<string> temp;
    //让temp存储vs中string的大写版本的代码
    return temp;
}

并这样使用它:

vector<string> vstr;
vector<string> vstr_copy1(vstr); //#1
vector<string> vstr_copy2(allcaps(vstr)); //#2

allcaps () 创建了对象 temp,该对象管理着 20000000 个字符;语句二使用 vector 和 string 的复制构造函数创建了一个 temp 的副本,然后删除了 temp,做了大量无用功。如果编译器直接把 temp 对数据的所有权转让给 vstr_copy2,将会更好。

实际上,我们可以把实际内容保留在原来地方,而之修改记录,这就是移动语义的本质,它避免了移动原始数据,而转为修改记录。

要实现移动语义,需要采取某种方式,让编译器知道什么时候需要复制。这就是右值引用发挥作用的地方。可定义两个构造函数,其中一个是常规复制构造函数,它使用 const 左值引用作为参数,如语句 #1。另一个是移动构造函数,它使用右值引用作为参数,该引用关联到右值实参,如语句 #2 中 allcaps (vstr) 的返回值。移动构造函数可能修改其实参,这意味着右值引用参数不应是 const。

# 如何使用

直接将变量的值赋值为参数的变量值,如果变量为指针,为了防止 double free,还需将参数的指针改为 nullptr。

例如:

Useless(Useless && f) : n(f.n)
{
	++ct;
	pc = f.pc;
	f.pc = nullptr;
	f.n = 0;
}

# 强制移动

移动构造函数和移动赋值运算符使用右值,如果要让它们使用左值,该怎么办?例如,将一个左值变量赋值给一个对象,并立刻丢弃这个变量。此时可以使用头文件 utility 中声明的函数 std::move。

更新于

请我喝[茶]~( ̄▽ ̄)~*

MikeMao 微信支付

微信支付

MikeMao 支付宝

支付宝

MikeMao 贝宝

贝宝