为什么C ++ 0x rvalue引用不是默认值?

时间:2009-05-09 22:46:39

标签: c++ c++11 lvalue rvalue

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

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

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

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

2 个答案:

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

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

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