2

This is follow up of question Is there a sequence point between return and expression in return statement? . The answer-er isn't replying to my comments , neither I'm unable to understand from his answer, nor I know how to bump the thread. So I created this question, my sincere apologies for doing this.

Consider the below code :

#include <iostream>
using namespace std;

struct foo{const char* bar ; foo(): bar("This is foo"){} };

foo returnByValue(){ return foo(); }
const foo& returnByConstRef() { return returnByValue();  } // *

int main() {
std::cout<< returnByConstRef().bar  <<std::endl; // is life of temp is extended in while this expression?
return 0;
}

My understanding is that returnByValue() expression (inside returnByConstRef()) is the copy of temporary object foo() (using copy ctor) . Now returnByConstRef() which is const reference to temp object returned by returnByValue() (copy of original temp() object in the code) , Now when I invoke returnByConstRef().bar why is it undefined behavior ?

Where is my thinking wrong? , does RVO does this?

Community
  • 1
  • 1
Angelus Mortis
  • 1,534
  • 11
  • 25

1 Answers1

3

This isn't due to RVO, the standard specifies that temporaries bound to returned values do not have their lifetime extended:

N3337 [class.temporary]/5: [...] The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:

  • [...]

  • The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.

  • [...]

For your example:

const foo& returnByConstRef() 
{ 
    return returnByValue();  
}

returnByValue() is a temporary which is being bound to the return value, kind of like this:

const foo& returnByConstRef() 
{ 
    const foo& _temporary_object = returnByValue();
    return _temporary_object;  
    //object referenced by _temporary_object is destroyed
}    

Such temporaries do not have their lifetime extended; they are destroyed on function exit. Maybe it would help you to think of it like this:

function returnByConstRef
    call returnByValue, put value on the stack
    put pointer to value in return register
    clear up stack, invalidating pointer to the value
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • please use easy language with example, I don't follow standard's language in this case. Your answer is very similar to the question link I posted in very start of this thread. sorry for my english also – Angelus Mortis Sep 23 '15 at 11:35
  • I wrote my thinking in the question , can you please tell where am I wrong and contradict me? :) Thanks. – Angelus Mortis Sep 23 '15 at 11:37
  • 1
    The bold paragraph basically says: "The lifetime of a temporary returned by a function cannot be extended.". There's nothing wrong with your understanding of the code, the C++ standard just says that what you're trying to do is not allowed. It may even accidentally compile & work but there is no guarantee what will happen (a.k.a. undefined behavior). In case you're wondering why the standard forbids you from doing this, I have no clue, maybe someone else does. – Excelcius Sep 23 '15 at 11:59
  • @Excelcius you're overgeneralizing what the bold paragraph states. it talks about temporaries *bound* to return values – Piotr Skotnicki Sep 23 '15 at 12:41
  • so the `_temporary_object` is deleted when function `returnByConstRef()` exits in your example code, right? Thanks – Angelus Mortis Sep 23 '15 at 12:59
  • @AngelusMortis the object referenced by `_temporary_object` is destroyed when the function exits, yes. – TartanLlama Sep 23 '15 at 13:00
  • now since `_temporary_object` is deleted, object referenced by it also get deleted. now I get it. – Angelus Mortis Sep 23 '15 at 13:01
  • 1
    @PiotrSkotnicki I know, but OP wanted easy language because it seems he had troubles understanding this paragraph. That's why I left out parts which should be clear in the context of this question. – Excelcius Sep 23 '15 at 13:02
  • 1
    @AngelusMortis note that there is a distinction in C++ between *deleted* and *destroyed*. Deleting usually refers to a `delete` expression on some pointer, whereas destruction usually refers to a variable coming to the end of its lifetime. – TartanLlama Sep 23 '15 at 13:04
  • got it @TartanLlama Thanks again for answer. I wished I could upvote your answer more than 1 time :) – Angelus Mortis Sep 23 '15 at 13:05