1

Life time of temporary objects last until the full length of the expression in which it was created when used without references.

Consider the following:

 class My
 {
   int i;
   public:
     void increment()
     {
       i++;
     }
 };

 My withOutConst()
 {
   return My();
 }

 const My withConst()
 {
   return My();
 }

 int main()
 {
   My ob;
   withOutConst().increment();  // Case 1
   withConst().increment();     // Case 2

   return 0;
 }

As I understand the compiler creates a temporary object( of type const My) to hold the return value in the above cases. And, I am trying to modify the temporary object.

(1) Compiles fine and

(2) Results in a compile time error with the error:

error: passing 'const My' as 'this' argument of void My::increment() discards qualifiers

That means basically this is of type My and not const My as it is called for a non-const function.

My question:

I am trying to modify a temporary object of type const My by calling a non-const member function.

Then why don't I get the same error in case(1) because I am operating over an object of the type const My in both the cases.

I understand that this is related to the return type of the functions but am unable to fully comprehend because at the end it boils down to the function(void My::increment()) which is trying to modify temporaries of type const My in both the cases.

Uchia Itachi
  • 5,287
  • 2
  • 23
  • 26
  • It's been a long time since I did something in C++, but what purpose does the `My ob;` serve? – Filip Vondrášek Aug 20 '13 at 18:09
  • 1
    In case 1, your temporary is not `const`. So you can call non-const methods on it. This isn't the case in Case 2. – juanchopanza Aug 20 '13 at 18:09
  • An important thing to remember here is that you created two functions which essentially create objects `My x` and `const My y`, respectively. So, really, your `My ob` serves no actual purpose. It is likely the compiler simply has optimized this to what I noted above. – RageD Aug 20 '13 at 18:11
  • 1
    possible duplicate? http://stackoverflow.com/questions/4701558/are-temporary-objects-in-c-const-indeed – LarryPel Aug 20 '13 at 18:22

5 Answers5

2

A temporary has a type, that type can be const, and it can be non-const. You can call a non-const member function only on a non-const object. withOutConst() yield a temporary of type My, withConst() yields a temporary of type const My.

Maybe you have the misconception that a temporary is always const? If that is the case, then it is wrong.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • But I was going through `thinking in C++` it says that compiler automatically makes temporaries `const`. This led me to this question. – Uchia Itachi Aug 20 '13 at 18:17
  • @UchiaItachi: The book can say that, but temporaries are not `const` automagically, as you have already noticed. – David Rodríguez - dribeas Aug 20 '13 at 18:21
  • Yes, I agree because its working in the above case. But, consider I have one more function `void change(My &ref)` and I am calling it as `change(withOutConst())` I get an error here too, but it vanishes if the function is `void change(const My &ref)` doesn't that mean the temporary is of `const` type? – Uchia Itachi Aug 20 '13 at 18:23
  • @UchiaItachi: I understand. The question is fine, the answer is just what it is :) – David Rodríguez - dribeas Aug 20 '13 at 18:25
  • @UchiaItachi: No, it does not mean that the temporary is `const`. the calls to both `withOutConst()` and `withConst()` are *rvalue* expressions, `const My&` and `My&` are both *lvalue*-references. You cannot bind a (modifiable) *lvalue* reference to an *rvalue*. There is a special rule in the language that allows binding a `const` *lvalue* reference to the *rvalue* (whether `const` or not) by extending the lifetime of the *rvalue* to match the lifetime of the bound reference. But that is a specific rule for binding references. – David Rodríguez - dribeas Aug 20 '13 at 18:49
0

Then why don't I get the same error in case(1) because I am operating over an object of the type const My in both the cases.

That simply isn't true.

 My withOutConst()
 {
   return My();
 }

 const My withConst()
 {
   return My();
 }

withOutConst returns an object of type My, while withConst() returns an object of type const My. Even though in both cases you are using them as temporaries, their underlying type My and const My are exactly as coded in the function signatures.

Chad
  • 18,706
  • 4
  • 46
  • 63
0
  1. Returns a temporary non-const object, calls the function on it, then it goes out of scope.
  2. Returns a temporary const object, which does not allow non-const function to be called.

A temporary object does not have to be const.

Neil Kirk
  • 21,327
  • 9
  • 53
  • 91
0

As I understand the compiler creates a temporary object( of type const My) to hold the return value in the above cases.

No. The return value of withOutConst() is not const, since you didn't declare it const. The observed behaviour follows from that.

You may be confusing being const with being an rvalue. In many situations, an rvalue can't be modified; but you can call a nonconstant member function on one.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

If this is a simplified version of something you're trying to do in a more complex code base, where you still want to use some some sort of counter on a const object, then you need to mark your "i" variable as "mutable". Like so:

class My
{
   mutable int i;
public:
   void increment()
   {
      i++;
   }
};