我正在学习右值引用,教程告诉我:
X foo(); X x; x = foo();
很明显,在 x 和临时对象之间交换资源指针(句柄),然后让临时对象的析构函数破坏 x 的原始资源是可以的,而且效率更高。
换句话说,在赋值右侧是 rvalue 的特殊情况下,我们希望复制赋值运算符像这样操作。
那么,这是否意味着函数的返回值在默认情况下始终是常量,因此是右值?如果是:它们总是不变的,还是也有例外?
我正在学习右值引用,教程告诉我:
X foo(); X x; x = foo();
很明显,在 x 和临时对象之间交换资源指针(句柄),然后让临时对象的析构函数破坏 x 的原始资源是可以的,而且效率更高。
换句话说,在赋值右侧是 rvalue 的特殊情况下,我们希望复制赋值运算符像这样操作。
那么,这是否意味着函数的返回值在默认情况下始终是常量,因此是右值?如果是:它们总是不变的,还是也有例外?
那么,这是否意味着函数的返回值在默认情况下始终是常量,因此是右值?如果是:它们总是不变的,还是也有例外?
不,如果它们不返回引用类型(cv T&
或cv T&&
),它们就是右值。如果它们的返回类型是 const 限定的,则它们是常量。
这意味着函数的返回值X foo()
是一个右值(prvalue,如果你想要新的standardese),而不是一个常量。此外,在类似 的表达式中x = foo()
,我们通常不关心分配期间的临时变化,这几乎是移动语义背后的想法。
Rvalue-ness 和 constant-ness 不是同义词,而是有点正交。具有以下定义:
struct X {};
const X x;
const X f();
int X();
我们可以对以下表达式进行分类:
x; // constant lvalue
f(); // constant rvalue
g(); // non-constant rvalue
至于您的特定问题:不,并非所有右值表达式都是常量。
您可能会混淆类型、对象和表达式。只有表达式具有左值/右值的概念。表达式 foo();
是类型的右值X
。因此,该语句x = foo();
将调用 - 如果可能的话 - 的成员函数X::operator=(X &&)
。x
否则,它将绑定到标准X::operator=(X const &)
,因为右值绑定到 const-references。
请注意,理论上可能有恒定的右值,例如,如果您有一个声明为X const bar();
. 然后bar()
不会绑定到X&&
,而只会绑定到X const &&
(以及到X const &
)。但是,在实践中这没有用。
请参阅上一个问题,它告诉我们右值表达式既不是隐含的const
类型,也不是它们所代表的对象本质上是不可变的。
但是,在某些情况下,通过右值修改对象是未定义的(或禁止的——我忘记了)。这似乎确实为通过右值访问的对象产生了一种有条件的固有不变性,并且评估函数调用的结果通常是 - 尽管并非总是如此!— 一个右值表达式。
§5.2.2/10(在 N3225 中)指出:
如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用是左值,如果结果类型是对对象类型的右值引用,则为 xvalue,否则为纯右值。