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

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 cannot pass rvalue as a link argument other than const, but what I'm confused is why I can assign this value to r, as the code shows.

+6
source share
3 answers

Passing the rvalue rtByValue() function that expects the lvalue reference to fail, as this will require initializing the lvalue reference argument from rvalue. Β§8.5.3 / 5 describes how lvalue links can be initialized - I won’t give it in full, but basically says that an lvalue link can be initialized

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

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

On the other hand,

 rtByValue() = aa; 

ie, assigning to a temporary object, possibly due to:

(Β§3.10 / 5) To modify an object, an lvalue is required for the object, except that the class type rvalue can also be used to change its referent under certain circumstances. [Example: a member function called for an object (9.3) can modify the object. - end of example]

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

(So, if rtByValue() was supposed to return, for example, int , then the assignment would not work.)

+8
source

Because you can (but shouldn't!) Redefine operator =, so calling it on 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 in several 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 not promise that you will see the same results.

As you can see, assignment occurs, but any attempt to use the assigned object leads to implementation-specific behavior.

By the way, this applies only to custom types. This code:

 int v(){ return 2; } main(){ v()=4; } 

not compiled.

+1
source

@ddriver This prints the number 7, as you 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; } 
0
source

All Articles