它表示一个rvalue引用。Rvalue引用将只绑定到临时对象,除非另有显式生成。它们用于在某些情况下使对象更高效,并提供一种称为完美转发的工具,这极大地简化了模板代码。
在C+03中,您无法区分不可变的lvalue和rvalue的副本。std::string s;std::string another(s); // calls std::string(const std::string&);std::string more(std::string(s));
// calls std::string(const std::string&);
在C+0x中,情况并非如此。std::string s;std::string another(s);
// calls std::string(const std::string&);std::string more(std::string(s)); // calls std::string(std::string&&);
考虑一下这些构造函数背后的实现。在第一种情况下,字符串必须执行一个副本来保留值语义,这涉及到一个新的堆分配。但是,在第二种情况下,我们预先知道传递给构造函数的对象将立即销毁,并且不必保持不变。在这个场景中,我们可以有效地交换内部指针,而根本不执行任何复制,这大大提高了效率。移动语义对任何具有昂贵或禁止复制内部引用资源的类都有好处。考虑到std::unique_ptr-现在我们的类可以区分临时的和非临时的,我们可以使移动语义正确工作,以便unique_ptr不能复制,但可以移动,这意味着std::unique_ptr可以合法地存储在标准容器中,分类等,而C+03的std::auto_ptr不能。
现在我们考虑rvalue引用的其他用途-完美转发。考虑将引用绑定到引用的问题。std::string s;std::string& ref = s;(std::string&)& anotherref = ref; // usually expressed via template
不记得C+03对此有何看法,但在C+0x中,在处理rvalue引用时得到的结果类型是至关重要的。对类型T的rvalue引用,其中T是引用类型,成为T类型的引用。(std::string&)&& ref // ref is std::string&(const std::string&)&& ref // ref is const std::string&(std::string&&)&& ref
// ref is std::string&&(const std::string&&)&& ref // ref is const std::string&&
考虑最简单的模板函数-min和max。在C+03中,您必须手动重载Const和non-Const的所有四个组合。在C+0x中,它只是一个过载。结合各种模板,这可以实现完美的转发。template auto min(A&& aref, B&& bref) {
// for example, if you pass a const std::string& as first argument,
// then A becomes const std::string& and by extension, aref becomes
// const std::string&, completely maintaining it's type information.
if (std::forward(aref) (bref))
return std::forward(aref);
else
return std::forward(bref);}
我取消了返回类型的推断,因为我不记得它是如何即时完成的,但是这个min可以接受任意的lvalue、rvalue、const值的组合。