C++ function returns a rvalue, but that can be assigned a new value?

落花浮王杯 提交于 2019-12-17 18:57:59

问题


The code is as follows:

 #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;
 }

The g++ compiler gives the following error:

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&)’

It says that I can't pass an rvalue as an argument of a non-const reference, but what I'm confused about is why I can assign to this rvalue, just as the code shows.


回答1:


Passing the rvalue rtByValue() to a function that expects an lvalue reference doesn't work because this would require the lvalue reference argument to be initialized from an rvalue. §8.5.3/5 describes how lvalue references can be initialized – I won't quote it in full, but it basically says that an lvalue reference can be initialized

  • either from another lvalue reference
  • or something that can be converted to an lvalue reference of an intermediary type
  • or from an rvalue, but only if the lvalue reference we initialize is a const-reference

Since the argument we need to initialize is not a const-reference, none of this applies.

On the other hand,

rtByValue() = aa; 

i.e., assigning to a temporary object, is possible because of:

(§3.10/5) An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [ Example: a member function called for an object (9.3) can modify the object. — end example ]

So this works only because A is of class-type, and the (implicitly defined) assignment operator is a member function. (See this related question for further details.)

(So, if rtByValue() were to return, for example, an int, then the assignment wouldn't work.)




回答2:


Because you can (but shouldn't!) override operator= such that calling it on an rvalue makes sense. Consider the following code:

#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;
}

Now let's compile it a few ways:

$ 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

I can't promise you'll see the same results.

As you can see, the assignment happens, but any attempt to use the object that got assigned results in implementation-specific behaviour.

Incidentaly, this only applies to user-defined types. This code:

int v(){
  return 2;
}

main(){
  v()=4;
}

doesn't compile.




回答3:


@ddriver This outputs number 7, as I would expect.

#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;
 }


来源:https://stackoverflow.com/questions/15824750/c-function-returns-a-rvalue-but-that-can-be-assigned-a-new-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!