Duc*_*een 6 c++ reference move move-semantics c++11
一个人可能有一个函数void setData(std::string arg); ,并通过setData(std::move(data));调用move构造函数调用它,他也会这样做void setData(std::string && arg);(除了他将被迫将数据移入其中).如果对简单情况应该使用move,那么编译器决定做什么呢?
所以我的问题是:&&不仅要用于编译器,还要用于通用代码(例如为其他开发人员创建的API成员)?
比较void setData(std::string arg)和void setData(std::string&& arg). 在第一种情况下,我假设setData将数据移动到位
class Widget {
std::string data;
public:
void setData(std::string data) { this->data = std::move(data); }
};
Run Code Online (Sandbox Code Playgroud)
如果我们这样称呼它
w.setData(std::move(data));
Run Code Online (Sandbox Code Playgroud)
我们将调用一次移动构造函数来构造函数参数,并调用一次移动赋值运算符将数据移动到成员变量中。所以总共有两步。
但是如果我们像这样重载右值引用:
class Widget {
std::string data;
public:
void setData(std::string&& data) { this->data = std::move(data); }
};
Run Code Online (Sandbox Code Playgroud)
您只会接到一次对移动赋值运算符的调用。你可能会说“但是搬家很便宜!” 这可能是真的。在某些情况下,它们并不便宜(例如std::array),并且在大多数编译器实现小字符串优化(SSO)的情况下std::string,因此对于小字符串,移动并不比副本便宜。
按值传递的论点通常是您可以优化左值和右值,而不必提供两个重载void setData(const std::string& arg)和void setData(std::string&& arg)。因此,让我们比较一下如果我们将左值传递给void setData(std::string arg)vs会发生什么void setData(const std::string& arg)。在第一种情况下,您将获得一个无条件副本,然后获得一个移动分配。在第二种情况下,你只得到一项任务。额外的移动分配可能微不足道,但无条件复制可能比分配昂贵得多。如果您对同一对象调用setData多次,则分配可能能够重新使用现有容量并避免重新分配。无条件副本始终必须进行分配。
这些考虑因素在实践中可能微不足道,但值得注意。
r 值参考参数的另一个用途是记录/强制所有权转移。假设您有一些可复制和可移动的大型对象,那么您可能只提供它void setData(BigData&& data)来强制执行移动。除了减少有人意外复制的可能性之外,它还证明我们正在获取数据的所有权。您也不一定需要移动整个对象,您可能只窃取对象的一部分。