C ++函数返回一个rvalue,但是可以为其赋值?

时间:2013-04-05 02:04:13

标签: c++ assignment-operator temporary rvalue

代码如下:

 #include <iostream>
 using namespace std;

 class A {

 };

 A rtByValue() {
return A();
 }

 void passByRef(A &aRef) {
    // do nothing
 }

 int main() {
    A aa;
    rtByValue() = aa;            // compile without errors
    passByRef(rtByValue());      // compile with error 

    return 0;
 }

g ++编译器出现以下错误:

d.cpp: In function ‘int main()’:
d.cpp:19:23: error: invalid initialization of non-const reference of type ‘A&’ from an rvalue of type ‘A’
d.cpp:12:6: error: in passing argument 1 of ‘void passByRef(A&)’

它说我不能将rvalue作为非const引用的参数传递,但我很困惑的是为什么我可以分配给这个rvalue,就像代码所示。

3 个答案:

答案 0 :(得分:8)

将rvalue rtByValue()传递给期望左值引用的函数不起作用,因为这需要从右值初始化左值引用参数。 §8.5.3/ 5描述了如何初始化左值引用 - 我不会完全引用它,但它基本上表示可以初始化左值引用

  • 来自另一个左值参考
  • 或可以转换为中间类型左值引用的内容
  • 或来自右值,但仅当我们初始化的左值参考是const-reference

由于我们需要初始化的参数不是const-reference,因此不适用。

另一方面,

rtByValue() = aa; 

即分配给临时对象是可能的,因为:

  

(§3.10/ 5)为了修改对象,对象的左值是必要的,除了在某些情况下也可以使用类类型的右值来修改它的指示对象。 [示例:调用对象(9.3)的成员函数可以修改对象。 - 结束例子]

所以这只是因为A属于类型,而(隐式定义的)赋值运算符是成员函数。 (有关详细信息,请参阅this related question。)

(因此,如果要返回rtByValue(),例如int,则分配将无效。)

答案 1 :(得分:2)

因为你可以(但不应该!)覆盖operator =,这样在rvalue上调用它是有意义的。请考虑以下代码:

#include<iostream>

using namespace std;

class foo;

foo* gotAssigned = NULL;
int assignedto = -1;

class foo {
public:
  foo(int v) : val(v) {}
  foo& operator=(int v) {
    assignedto=v;
    gotAssigned = this;
    val = v;
    return *this;
  }
  int val;
};

foo theFoo(2);

foo returnTheFooByValue() {
  return theFoo;
}

main() {
  returnTheFooByValue()=5;
  cout << "[" << assignedto << "] " << theFoo.val << " versus " << gotAssigned->val << endl;
}

现在让我们以几种方式编译它:

$ g++ -O0 -o rveq rveq.cc && ./rveq
[5] 2 versus 5
$ g++ -O1 -o rveq rveq.cc && ./rveq
[5] 2 versus 2
$ g++ -O4 -o rveq rveq.cc && ./rveq
[5] 2 versus -1218482176

我不能保证你会看到相同的结果。

正如您所看到的,分配发生了,但是任何使用已分配对象的尝试都会导致特定于实现的行为。

事实上,此适用于用户定义的类型。这段代码:

int v(){
  return 2;
}

main(){
  v()=4;
}

无法编译。

答案 2 :(得分:0)

@ddriver输出数字7,正如我所料。

#include <iostream>
 using namespace std;

 class A {
 public:
     int i;
     A() {i = 0x07;}
 };

 A rtByValue() {
return A();
 }

 void passByRef(A &aRef) {
     cout << aRef.i;
 }

 int main() {
    passByRef(rtByValue());
    return 0;
 }