简单的答案是,您应该像为常规引用代码一样为右值引用编写代码,并且应该在99%的时间里对它们进行相同的心理处理。这包括有关返回引用的所有旧规则(即,永不返回对局部变量的引用)。
除非您编写的模板容器类需要利用std :: forward并能够编写采用左值或右值引用的泛型函数,否则这或多或少都是正确的。
move构造函数和move分配的一大优点是,如果定义了它们,则编译器可以在无法调用RVO(返回值优化)和NRVO(命名为返回值优化)的情况下使用它们。对于通过方法有效地按值返回昂贵的对象(例如容器和字符串)而言,这是巨大的。
现在,右值引用使事情变得有趣,您还可以将它们用作常规函数的参数。这使您可以编写对const引用(const foo&other)和rvalue引用(foo && other)都具有重载的容器。即使参数太笨拙以至于不能仅通过构造函数调用来传递,也仍然可以做到:
std::vector vec;
for(int x=0; x<10; ++x)
{
// automatically uses rvalue reference constructor if available
// because MyCheapType is an unamed temporary variable
vec.push_back(MyCheapType(0.f));
}
std::vector vec;
for(int x=0; x<10; ++x)
{
MyExpensiveType temp(1.0, 3.0);
temp.initSomeOtherFields(malloc(5000));
// old way, passed via const reference, expensive copy
vec.push_back(temp);
// new way, passed via rvalue reference, cheap move
// just don't use temp again, not difficult in a loop like this though . . .
vec.push_back(std::move(temp));
}
STL容器已更新,几乎所有内容(哈希键和值,向量插入等)都具有移动重载,在这里您将最常看到它们。
您也可以将它们用于普通函数,如果仅提供右值引用参数,则可以强制调用者创建对象并让函数进行移动。这不是一个很好的例子,但在我的渲染库中,我为所有加载的资源分配了一个字符串,以便更轻松地查看调试器中每个对象代表什么。该接口是这样的:
TextureHandle CreateTexture(int width, int height, ETextureFormat fmt, string&& friendlyName)
{
std::unique_ptr<TextureObject> tex = D3DCreateTexture(width, height, fmt);
tex->friendlyName = std::move(friendlyName);
return tex;
}
它是“泄漏抽象”的一种形式,但允许我利用我必须在大多数时间已经创建字符串的事实,而避免再次复制它。这并不是完全高性能的代码,但是随着人们逐渐掌握此功能,它就是一个很好的例子。这段代码实际上要求变量要么是调用的临时变量,要么是调用std :: move的变量:
// move from temporary
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, string("Checkerboard"));
要么
// explicit move (not going to use the variable 'str' after the create call)
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, std::move(str));
要么
// explicitly make a copy and pass the temporary of the copy down
// since we need to use str again for some reason
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, string(str));
但这不会编译!
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, str);