20

即将推出的 C++ 标准 C++0x 的一个很酷的新特性是“右值引用”。右值引用类似于左值(普通)引用,除了它可以绑定到临时值(通常,临时只能绑定到const引用):

void FunctionWithLValueRef(int& a) {…}
void FunctionWithRValueRef(int&& a) {…}

int main() {
     FunctionWithLValueRef(5); // error, 5 is a temporary
     FunctionWithRValueRef(5); // okay
}

那么,他们为什么要发明一种全新的类型,而不是仅仅取消对普通引用的限制以允许它们绑定到临时对象?

4

2 回答 2

44

这将毫无意义。您将更改函数中的事物,并且更改将立即丢​​失,因为该事物实际上是临时的。

新类型的原因源于需要能够决定什么实际上是右值,什么不是。只有这样你才能真正将它们用于它们所使用的很酷的东西。

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));
}

现在,如果您有一些右值并将其传递给 toupper,则可以直接修改右值,因为我们知道临时的东西无论如何都是一次性的,所以我们也可以直接更改它而不需要复制它。同样,同样的观察也用于移动构造函数和移动赋值。右手边没有被复制,只是它的东西被偷走并移到了*this.

如果您说右值可以绑定到非 const 左值引用,那么您将无法确定最终是引用左值(命名对象)还是右值(临时)。


它可能鲜为人知,但无论如何有用,您可以将左值或右值引用限定符放在成员函数上。这是一个示例,它自然地将右值引用的现有语义扩展到隐式对象参数:

struct string {
    string& operator=(string const& other) & { /* ... */ }
};

现在,你不能再说

string() = "hello";

这是令人困惑的,并且在大多数情况下并没有真正的意义。上面所做的&就是说赋值运算符只能在左值上调用。右值也可以这样做,方法是把&&.

于 2009-05-09T22:58:52.793 回答
12

因为添加一种新的引用允许您编写方法的两个重载:

void CopyFrom(MyClass &&c)
{
    dataMember.swap(c);
}

void CopyFrom(const MyClass &c)
{
    dataMember.copyTheHardWay(c);
}

接受新类型引用的版本允许修改它接收的变量,因为该变量不会在其他任何地方使用。所以它可以“窃取”它的内容。

这就是添加此功能的全部原因;保留一种类型的参考不会达到预期的目标。

于 2009-05-09T22:59:12.870 回答