即将推出的C ++标准C ++ 0x的一个很酷的新功能是“右值引用”。右值引用类似于左值(正常)引用,除了它可以绑定到临时值(通常,临时值只能绑定到const
引用):
void FunctionWithLValueRef(int& a) {...}
void FunctionWithRValueRef(int&& a) {...}
int main() {
FunctionWithLValueRef(5); // error, 5 is a temporary
FunctionWithRValueRef(5); // okay
}
那么,为什么他们发明了一个全新的类型,而不仅仅是删除对普通引用的限制以允许它们绑定到临时引用?
答案 0 :(得分:43)
这将毫无意义。您将更改函数中的内容,并且更改将立即丢失,因为该内容实际上是临时的。
新类型的原因源于需要能够确定实际上是什么的右值和什么不是。只有这样,你才能真正使用它们来实现它们所使用的很酷的东西。
string toupper(string && s) { // for nonconst rvalues
for(char &c : s) make_uppercase(c);
return move(s); // move s into a returned string object
}
string toupper(string const& s) { // for the rest
// calls the rvalue reference version, by passing
// an rvalue copy.
return toupper(string(s));
}
现在,如果你有一些rvalue并将它传递给toupper,rvalue可以直接修改,因为我们知道临时是一个扔掉的东西,所以我们也可以改变它而不需要复制它。此外,同样的观察用于称为移动构造函数和移动赋值的东西。右侧不会被复制,但它的东西只是被偷走并移到*this
。
如果你要说rvalues可以绑定到非const左值引用,那么你将无法弄清楚它是否最后引用了左值(命名对象)或右值(临时值)。
它可能知之甚少,但无论如何有用,你可以在成员函数上放置左值或右值引用限定符。下面是一个示例,它自然地将rvalue引用的现有语义扩展为隐式对象参数:
struct string {
string& operator=(string const& other) & { /* ... */ }
};
现在,你不能再说了
string() = "hello";
这令人困惑,而且大部分时间都没有意义。上面&
所做的是说赋值运算符只能在左值上调用。通过放置&&
可以对rvalues进行相同的操作。
答案 1 :(得分:12)
因为添加新类型的引用允许您编写方法的两个重载:
void CopyFrom(MyClass &&c)
{
dataMember.swap(c);
}
void CopyFrom(const MyClass &c)
{
dataMember.copyTheHardWay(c);
}
允许接受新类型引用的版本修改它接收的变量,因为该变量不会在其他任何地方使用。所以它可以“窃取”它的内容。
这是添加此功能的全部原因;保留一种参考不会达到预期目标。