3

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 ;-)

Community
  • 1
  • 1
oHo
  • 51,447
  • 27
  • 165
  • 200

8 Answers8

13

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
Pete Becker
  • 74,985
  • 8
  • 76
  • 165
8

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).

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Well, you can bind temporaries to rvalue references (and subsequently take its address), so the object isn't any less "real" than one that is a named variable. – Kerrek SB Nov 14 '12 at 19:37
3

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();
}
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • +1 Thank you for your comment on my answer, I am updating ;-) – oHo Nov 14 '12 at 19:31
  • @Kerrek Sorry about the goof up in trying to *fix* your example. I'd forgotten about the `bar` *function* in the question that returns a `C` :) – Praetorian Nov 14 '12 at 19:44
3

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.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
1

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.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
1

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
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

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.)

zneak
  • 134,922
  • 42
  • 253
  • 328
  • Except when it does make sense... like a temporary `std::string` constructed from a string literal. – Kerrek SB Nov 14 '12 at 19:28
  • @KerrekSB, how could it make sense to modify a string literal? You're already not supposed to assign string literals to `char*` variables. How is it better for `std::string`s? And who's going to pick up the result? – zneak Nov 14 '12 at 21:09
  • Suppose you have a function that wants to further modify the string and then return that new string. Its signature should be `std::string(std::string s)`, and it would modify `s` and return it. You want to be able to call this on a raw string literal. Binding modifiably to the temporary string that's constructed at the call site is very useful (and that's what move semantics were invented for). – Kerrek SB Nov 14 '12 at 23:32
  • @KerrekSB, it feels like you stopped reading at the first sentence. – zneak Nov 15 '12 at 00:00
0

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() );
}            
oHo
  • 51,447
  • 27
  • 165
  • 200
  • 1
    Objects aren't temporary. *Values* are. And the objects which are temporary values are *not* constant! – Kerrek SB Nov 14 '12 at 19:29
  • Hi @KerrekSB. Do you mean my sentence _"To confirm temporary objects are const [...]"_ is wrong? What do you advice me to write? – oHo Oct 19 '13 at 16:50
  • 1
    Not sure. The point is that the object created by `C()` is not const. The reason you can't compile the last bit of code is that rvalues don't bind to non-const lvalue references, but the object is not const. You can say `C().f()` if `C::f` is a non-const member function. I don't really mind the verbal confusion in colloquial language between "object" and "value", but I thought that in this case it was probably the underlying reason for your final (wrong) conclusion. – Kerrek SB Oct 19 '13 at 16:56