简单的答案是,您应该像编写常规引用代码一样为右值引用编写代码,并且在99%的时间内,您应该在精神上对它们进行相同的处理。这包括所有关于返回引用的旧规则(即永远不要返回对局部变量的引用)。
除非你正在编写一个模板容器类,需要利用std::forward,并且能够编写一个接受左值或右值引用的泛型函数,否则这或多或少是正确的。
move构造函数和move赋值函数的最大优点之一是,如果你定义了它们,编译器可以在RVO(返回值优化)和NRVO(命名返回值优化)调用失败的情况下使用它们。这对于有效地从方法中返回容器和字符串等昂贵的对象来说是相当大的。
右值引用的有趣之处在于,你也可以将它们用作普通函数的参数。这允许你编写对const引用(const foo& other)和右值引用(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"));
or
// 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));
or
// 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);