Question

This code does not compile:

class C {};

void foo (C& c) {}

C bar() { return C(); }

int main()              
{
  foo(bar());
}               

Compilation error (GCC 4.1.2) in line foo(bar()):

invalid initialization of non-const reference of type 'C&' from a temporary of type 'C'

As bar() returns a mutable object, it should compile...
Why C++ does not allow this above code?


EDIT: I have summarize in an answer below all good ideas from all answers ;-)

Was it helpful?

Solution

The applicable rule here is that you can't create a non-const reference to a temporary object. If foo was declared as foo(const C&) the code would be okay.

The temporary object itself is not const, though; you can call non-const member functions on it, e.g., bar().non_const_member_function().

With C++11, foo can be written to take an rvalue reference; in that case, the call would be okay:

void foo(C&&);
foo(bar());  // okay

OTHER TIPS

It's because the value returned by bar is a temporary value. As it's existence is temporary, you can't use a pointer or reference to that.

However, if you store a copy of that temporary, as in your second change, you no longer pass a reference to a temporary object to foo, but a reference to a real tangible object. And in the first case, when you change to a reference to a constant object, the compiler makes sure the temporary object stays around long enough (as per the C++ specification).

The issue is not with the declaration of bar but with that of foo. foo takes a non-const reference, and temporaries can only bind to const references (which then extends the lifetime of the temporary to match that of the reference it is bound to).

Allowing a non-const reference to bind to a temporary doesn't make much sense. A non-const reference implies that it will modify whatever object is bound to it. Modifying a temporary serves no purpose since its lifetime is limited and the changes will be lost as soon as it goes out of scope.

Modifiable (lvalue-)references do not bind to temporary values. However, const-references do bind to temporary values. It has nothing to do with whether the object returned by value is const or not; it's simply a matter of whether the expression is temporary or not.

For example, the following is valid:

struct C { void i_am_non_const() {} };

int main()
{
    bar().i_am_non_const();
}

It is a design choice. There is nothing inherently impossible here. Just a design choice.

In C++11, you have a third alternative which is also superior alternative:

void foo(C && c) {} 

That is, use rvalue-references.

It's not const, but it is a temporary rvalue. As such, it can't bind to a non-const lvalue reference.

It can bind to a const or rvalue reference, and you can call member functions (const or not) on it:

class C { void f(); };

void foo_const(C const &);
void foo_rvalue(C &&);

foo_const( bar() );  // OK
foo_rvalue( bar() ); // OK
bar().f();           // OK

The real, hard truth is that it makes no sense to get a reference to a temporary value.

The big point of passing an object by reference is that it allows you to modify its state. However, in the case of a temporary, by its very nature, it would not be particularly helpful to be able to modify it, since you have no way of getting another reference to it later in your code to see the changes.

However, this is somewhat different in the case you have a const reference. Since you'll only ever read from a const reference, it makes total sense to be able to use temporaries there. This is why the compiler will "hack" around it for you, and give a more permanent address to temporaries that you want to "turn" into const references.

So, the rule is that you cannot get a non-const reference to a temporary value. (This slightly changed with C++11, where we have a new type of references that serve this exact purpose, but methods are expected to deal with those in a special way.)

Thank you all for your answers :-)
Here I gather your good ideas ;-)

Answer

Return by value is not const. For example, we can call non-const member functions of return by value:

class C { 
  public:
    int x;
    void set (int n) { x = n; }  // non-const function
};

C bar()  { return C(); }

int main ()
{
    bar.set(5); // OK
}

But C++ does not allow non-const references to temporary objects.
However C++11 allow non-const rvalue-references to temporary objects. ;-)

Explanation

class C {};

void foo (C& c) {}

C bar()  { return C(); }
//bar() returns a temporary object
//temporary objects cannot be non-const referenced

int main()
{
  //foo() wants a mutable reference (i.e. non-const)
  foo( bar() ); // => compilation error     
}                 

Three fixes

  1. Change foo declaration

      void foo (const C& c) {}
    
  2. Use another object

      int main()              
      {
        C c;
        foo( c = bar() );
      }
    
  3. Use C++11 rvalue-reference

      void foo(C && c) {}
    

Moreover

To confirm temporary objects are const, this above source code fails for the same reason:

class C {};

void foo(C& c) {}

int main()                
{
  foo( C() );
}            
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top