6

As known, that standard C++11 guarantees that temporary object passed to a function will have been created before function call: Does standard C++11 guarantee that temporary object passed to a function will have been created before function call?

But, does standard C++11 guarantee that temporary object passed to a function will have been destroyed after the end of the function (not before)?

Working Draft, Standard for Programming Language C++ 2016-07-12: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf

§ 12.2 Temporary objects

§ 12.2 / 5

There are three contexts in which temporaries are destroyed at a different point than the end of the full expression. The first context is when a default constructor is called to initialize an element of an array with no corresponding initializer (8.6). The second context is when a copy constructor is called to copy an element of an array while the entire array is copied (5.1.5, 12.8). In either case, if the constructor has one or more default arguments, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any. The third context is when a reference is bound to a temporary.

Also:

§ 1.9 / 10

A full-expression is an expression that is not a subexpression of another expression. [ Note: in some contexts, such as unevaluated operands, a syntactic subexpression is considered a full-expression (Clause 5). — end note ] If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition. A call to a destructor generated at the end of the lifetime of an object other than a temporary object is an implicit full-expression. Conversions applied to the result of an expression in order to satisfy the requirements of the language construct in which the expression appears are also considered to be part of the full-expression.

Does it mean that standard C++11 guarantees that temporary object passed to a function will have been destroyed not before the function will end - and exactly at the end of the full expression?

http://ideone.com/GbEPaK

#include <iostream>
using namespace std;

struct T { 
    T() { std::cout << "T created \n"; }
    int val = 0;
    ~T() { std::cout << "T destroyed \n"; }
};

void function(T t_obj, T &&t, int &&val) {
    std::cout << "func-start \n";
    std::cout << t_obj.val << ", " << t.val << ", " << val << std::endl;
    std::cout << "func-end \n";
}

int main() {

    function(T(), T(), T().val);

    return 0;
}

Output:

T created 
T created 
T created 
func-start 
0, 0, 0
func-end 
T destroyed 
T destroyed 
T destroyed 

Can we say that the T destroyed will always be after the func-end?

And this:

function(T(), T(), T().val);

Is always equal to this:

{
    T tmp1; T tmp2; T tmp3;
    function(tmp1, tmp2, tmp3.val);
}
Community
  • 1
  • 1
Alex
  • 12,578
  • 15
  • 99
  • 195
  • 3
    Your final part starting with "And this:" is not true, no. (The left-to-rightness of the comma operator does not apply to function arguments.) Am looking forward to the proper answer to this good question. – Bathsheba Aug 15 '16 at 11:37
  • 2
    Do you not believe my answer? – NathanOliver Aug 15 '16 at 11:39
  • @Bathsheba Thank you! Typo fixed. – Alex Aug 15 '16 at 11:40
  • @Bathsheba No, [the one](http://stackoverflow.com/a/38837662/4342498) on the previous question. – NathanOliver Aug 15 '16 at 11:41
  • @Alex, it still doesn't apply. Replacing `,` with `;` has absolutely no effect in this case. – Bathsheba Aug 15 '16 at 11:45
  • @NathanOliver I believe. You said it as a supplement to another question. But you quoted standard, which shows only that all temporary objects created before the start of the function, but nothing has been said about the time of their lives. I think it deserves an additional question. – Alex Aug 15 '16 at 11:46
  • 1
    @Alex - There is a significant difference in that `tmp1`, `tmp2`, and `tmp3` are always created in that order. The `T()` values in the function call can be created in any order (the one the compiler finds "optimal"). – Bo Persson Aug 15 '16 at 11:46

1 Answers1

8

Well, you already quoted all the text that tells us the temporary's lifetime ends at the end of the full-expression. So, yes, "T destroyed" will always come last.

If the destruction had no observable side-effects then, per the as-if rule, it could actually happen at any time afterwards… but that's moot because, well, it wouldn't be observable.

However, the final two snippets you presented are not generally equivalent, because you fixed the order of construction/initialisation in a way that it wasn't before. Function arguments have an unspecified evaluation order. Again, though, for this particular T the difference is not observable.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 2
    Just a minor fix: you probably meant to say "will always come **last**". – Yehezkel B. Aug 15 '16 at 11:53
  • 1
    Thank you! "T destroyed" will always come first - or last (at the end)? About "the temporary's lifetime ends at the end of the full-expression" - But is this not observable in this case too? http://ideone.com/DuY0GQ Taken from: https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Execute-Around_Pointer#Solution_and_Sample_Code – Alex Aug 15 '16 at 11:54
  • @Yehezkel: Haha yeah oops obvs – Lightness Races in Orbit Aug 15 '16 at 11:58
  • @Alex: Not sure what you're asking re that new code. It exhibits the same behaviour as that described above. – Lightness Races in Orbit Aug 15 '16 at 11:59