The standard is not particularly explicit on the matter as far as I can tell, but here's what I've managed to get together:
Automatic storage duration objects are destroyed as per 6.7 when the block they
are declared in exits.
- 3.7.2
On exit from a scope, destructors (12.4) are called for all automatic storage
duration (3.7.2) (named objects and temporaries) that are declared in that scope,
in reverse order of their declaration.
- 6.6
A return statement with an expression of non-void type can be used only in functions
returning a value; the value of the expression is returned to the caller of the
function. The expression is implicitly converted to the return type of the function
in which it appears. A return statement can involve the construction and copy of a
temporary object (12.2).
- 6.6.3
Even when the creation of the temporary object is avoided (12.6), all the semantic
restrictions must be respected as if the temporary object was created.
- 12.2
This seems to generally confirm what James said: on return m_protVal;
, a temporary is created, and then destructors of all objects that must be destroyed are called in reverse order of their declaration (in this case, only the destructor of lock
is called). However, I am not entirely sure how to interpret the following:
Temporary objects are destroyed as the last step in evaluating the full-expression (1.9)
that (lexically) contains the point where they were created.
- 12.2
A full-expression is defined as "as expression that is not a subexpression of another expression". I don't know what part of return m_protVal
is the full expression: geordi says that this is a
decl'ion-seq → decl'ion → func-def → func-body → compound-stmt → stmt-seq → stmt → jump-stmt
while i
by itself is a
decl'ion-seq → decl'ion → func-def → func-body → compound-stmt → stmt-seq → stmt →
jump-stmt → … → id-expr → unqual-id → ident
This makes it unclear whether the temporary may be copied and destroyed prior to the rest of the destructors being called: I would say it may not, as return m_protVal;
causes the end of the block to be reached, but I can't find anything in the standard that would confirm this.
(On the other hand, I don't see any case where such behaviour would cause any breakage; nobody should have a pointer to the temporary so it being destroyed first is not an issue, and if the temporary had a pointer to a local variable, the problems come in when the temporary is destroyed later -- not that writing code like that is a good idea in any case.)