将从函数返回的Rvalue分配给另一个Rvalue

时间:2016-02-13 09:11:40

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

class Test {

public:

    int n1;

};

Test func() {

    return Test();

}

int main() {

    func() = Test();

}

这对我没有意义。如何以及为什么允许这样做?是不确定的行为?如果函数返回一个rvalue,那么如何将rvalue设置为另一个rvalue呢?如果我用任何原始类型尝试这个,它会给我一个像我期望的错误。

我知道左值是内存中的一个位置,创建临时左值(rvalue?)并将其赋值给另一个左值的函数也是如此?有人可以解释这种语法是如何工作的吗?

2 个答案:

答案 0 :(得分:7)

函数调用表达式的值类别实际上是一个右值。

实际上,您可能无法在rvalue基元上调用复制赋值运算符。 C中rvalues的历史定义实际上是它们可能不在分类左侧的区别。

但是类的赋值运算符有点不同。他们是正式的会员职能。没有规则可以阻止调用rvalues的成员函数。实际上,当函数有副作用时,它通常非常有用。

如何工作,好吧,临时调用复制赋值运算符,运算符复制右手参数,改变临时状态。在语句之后,临时对象被丢弃。没有UB,只是毫无意义的复制。

可以阻止在rvalue上调用副本分配,方法是使用这样的引用限定符声明运算符:#include<stdio.h> void helper(char *i) { printf("%c", *i); *i = 't'; printf("%c", *i); } void main() { char *g = "t"; helper(g); printf("%c", *g); 。 Ref-qualifiers仅在c ++ 11中稍后添加,因此(隐式)复制赋值不能指定为先前的ref-qualified。据推测,C ++ 11并没有改变隐式复制构造函数的限定符,以防止破坏分配给rvalue的旧代码,即使这样的赋值似乎毫无意义。 enter image description here建议您将ref限定符与用户定义的副本赋值运算符一起使用。

答案 1 :(得分:1)

value categories而言(至少对我而言)有一个相当陡峭的学习曲线,但我相信你的榜样上有terminology。所以

func()

确实返回 prvalue 并从C ++ Standard par返回。 3.10.5 (我只有当前draft,您的段落编号可能会有所不同)我们读到:

  

对象的左值是必要的,以便修改对象,除了类类型的右值也可用于在某些情况下修改其指示物。 [例子:一个成员函数调用了一个   object(9.3)可以修改对象。 - 结束例子]

因此,作为成员函数的赋值运算符(如标准中提到的示例)是规则的例外,允许修改rvalues。

这引起了编程界的许多批评,最极端的例子就是C++ FQA摘录:

  

(是的,糖衣死亡陷阱,你是无能为力的啦啦队。X& obj=a.b().c() - oops,b()是一个临时对象,c()返回一个引用!不应该分配给它引用。编译器警告的机会也不多。)

但在真正的C ++编程中,它industrial applications就像named parameter成语一样:

std::cout << X::create().setA(10).setB('Z') << std::endl;