Title
Order of destruction for temporaries bound to the returned value of a function
Status
cd2
Section
6.7.7 [class.temporary]
Submitter
Mike Miller

Created on 2007-08-14.00:00:00 last changed 143 months ago

Messages

Date: 2009-03-15.00:00:00

[Voted into the WP at the March, 2009 meeting.]

Date: 2008-06-15.00:00:00

Proposed resolution (June, 2008):

Change 6.7.7 [class.temporary] paragraph 5 as follows (converting the running text into a bulleted list and making the indicated edits to the wording):

... 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: as specified below.
  • A temporary bound to a reference member in a constructor's ctor-initializer (11.9.3 [class.base.init]) persists until the constructor exits.

  • A temporary bound to a reference parameter in a function call (7.6.1.3 [expr.call]) persists until the completion of the full expression containing the call.

  • A The lifetime of a temporary bound to the returned value in a function return statement (8.7.4 [stmt.return]) persists until the function exits is not extended; the temporary is destroyed at the end of the full-expression in the return statement.

The destruction of a temporary whose lifetime is not extended...

Date: 2007-08-14.00:00:00

In describing the order of destruction of temporaries, 6.7.7 [class.temporary] paragraphs 4-5 say,

There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression...

The second context is when a reference is bound to a temporary... A temporary bound to the returned value in a function return statement (8.7.4 [stmt.return]) persists until the function exits.

The following example illustrates the issues here:

    struct S {
        ~S();
    };

    S& f() {
        S s;            // #1
        return
            (S(),       // #2
             S());      // #3
    }

If the return type of f() were simply S instead of S&, the two temporaries would be destroyed at the end of the full-expression in the return statement in reverse order of their construction, followed by the destruction of the variable s at block-exit, i.e., the order of destruction of the S objects would be #3, #2, #1.

Because the temporary #3 is bound to the returned value, however, its lifetime is extended beyond the end of the full-expression, so that S object #2 is destroyed before #3.

There are two problems here. First, it is not clear what “until the function exits” means. Does it mean that the temporary is destroyed as part of the normal block-exit destructions, as described in 8.7 [stmt.jump] paragraph 2:

On exit from a scope (however accomplished), destructors (11.4.7 [class.dtor]) are called for all constructed objects with automatic storage duration (6.7.5.4 [basic.stc.auto]) (named objects or temporaries) that are declared in that scope, in the reverse order of their declaration.

Or is the point of destruction for #3 after the destruction of the “constructed objects... that are declared [emphasis mine] in that scope” (because temporary #3 was not “declared”)? I.e., should #3 be destroyed before or after #1?

The other problem is that, according to the recollection of one of the participants responsible for this wording, the intent was not to extend the lifetime of #3 but simply to emphasize that its lifetime ended before the function returned, i.e., that the result of f() could not be used without causing undefined behavior. This is also consistent with the treatment of this example by many implementations; MSVC++, g++, and EDG all destroy #3 before #2.

Suggested resolution:

Change 6.7.7 [class.temporary] paragraph 5 as indicated:

A The lifetime of a temporary bound to the returned value in a function return statement (8.7.4 [stmt.return]) persists until the function exits is not extended; it is destroyed at the end of the full-expression in the return statement.
History
Date User Action Args
2010-03-29 00:00:00adminsetstatus: wp -> cd2
2009-08-03 00:00:00adminsetstatus: dr -> wp
2009-03-23 00:00:00adminsetmessages: + msg2027
2009-03-23 00:00:00adminsetstatus: ready -> dr
2008-10-05 00:00:00adminsetstatus: review -> ready
2008-06-29 00:00:00adminsetmessages: + msg1684
2008-06-29 00:00:00adminsetstatus: drafting -> review
2007-10-09 00:00:00adminsetstatus: open -> drafting
2007-08-14 00:00:00admincreate