2

我正在学习右值引用,教程告诉我:

X foo();
X x;
x = foo();

很明显,在 x 和临时对象之间交换资源指针(句柄),然后让临时对象的析构函数破坏 x 的原始资源是可以的,而且效率更高。

换句话说,在赋值右侧是 rvalue 的特殊情况下,我们希望复制赋值运算符像这样操作。

那么,这是否意味着函数的返回值在默认情况下始终是常量,因此是右值?如果是:它们总是不变的,还是也有例外?

4

5 回答 5

3

那么,这是否意味着函数的返回值在默认情况下始终是常量,因此是右值?如果是:它们总是不变的,还是也有例外?

不,如果它们不返回引用类型(cv T&cv T&&),它们就是右值。如果它们的返回类型是 const 限定的,则它们是常量。

这意味着函数的返回值X foo()是一个右值(prvalue,如果你想要新的standardese),而不是一个常量。此外,在类似 的表达式中x = foo(),我们通常不关心分配期间的临时变化,这几乎是移动语义背后的想法。

于 2011-12-11T22:13:44.430 回答
3

Rvalue-ness 和 constant-ness 不是同义词,而是有点正交。具有以下定义:

struct X {};
const X x;
const X f();
int X();

我们可以对以下表达式进行分类:

x;       // constant lvalue
f();     // constant rvalue
g();     // non-constant rvalue

至于您的特定问题:不,并非所有右值表达式都是常量。

于 2011-12-11T22:15:11.770 回答
1

您可能会混淆类型对象表达式。只有表达式具有左值/右值的概念。表达式 foo();是类型的右值X。因此,该语句x = foo();将调用 - 如果可能的话 - 的成员函数X::operator=(X &&)x否则,它将绑定到标准X::operator=(X const &),因为右值绑定到 const-references。

请注意,理论上可能有恒定的右值,例如,如果您有一个声明为X const bar();. 然后bar()不会绑定到X&&,而只会绑定到X const &&(以及到X const &)。但是,在实践中这没有用。

于 2011-12-11T22:14:50.197 回答
1

请参阅上一个问题,它告诉我们右值表达式既不是隐含的const类型,也不是它们所代表的对象本质上是不可变的。

但是,在某些情况下,通过右值修改对象是未定义的(或禁止的——我忘记了)。这似乎确实为通过右值访问的对象产生了一种有条件的固有不变性,并且评估函数调用的结果通常是 - 尽管并非总是如此!— 一个右值表达式。

于 2011-12-11T22:15:45.290 回答
1

§5.2.2/10(在 N3225 中)指出:

如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用是左值,如果结果类型是对对象类型的右值引用,则为 xvalue,否则为纯右值。

于 2011-12-11T22:18:21.870 回答