Function parameters are not destroyed at that function's exit
c++
Solution
To elaborate from what by now can already be found in the comments:
Given `int f(Logger);`, when you write:
f(10);
this (conceptually) constructs a temporary `Logger` object, constructs the function parameter from that temporary object, calls the function, destroys the function parameter, and finally destroys the temporary object.
When you write:
f(f(10));
this (conceptually) constructs a temporary `Logger` object, constructs the function parameter from that temporary object, calls the function, destroys the function parameter, constructs a new temporary `Logger` object using the first function call's result, constructs the function parameter from that temporary object, calls the function, destroys the function parameter, and finally destroys the two temporary objects.
I'll avoid writing it out for `f(f(f(10)));` case.
Now, those two temporary objects can be omitted:
When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization. This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):
...
when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move
...
Since the function parameter and the temporary object have the same type, a compiler is allowed to treat them as the same object. The temporary object would be destroyed at the final stage, so the lifetime of the parameter does not come into play.
However, when copy elision isn't performed, for example because you configure the compiler not to, or because there is no copy to elide in the first place (see below), then the function parameters must indeed be destroyed when you say they should be, and you must see "Destruct (...)" before the second function invocation starts in all conforming C++11 implementations.
A parameter can be constructed without a temporary by using braces: you could re-work the call as
f({f({f({10})})});
Here, each parameter is list-initialised, which in this case does not involve temporary objects, and there are no copies to elide. This must destroy the function parameters as soon as the function `f` returns, before `f` is called again, in all C++11-conforming implementations, regardless of any `-felide-constructors` command-line options, and the fact that compilers do not do this is an area in which they fail to conform to C++11.
It's not quite as simple as that, though: CWG issue 1880 reads:
WG decided to make it unspecified whether parameter objects are destroyed immediately following the call or at the end of the full-expression to which the call belongs.
This would allow exactly what compilers do now: the parameters can be destroyed after the end of the full-expression, after the last `f` has returned. The exact literal text of C++11 isn't what current compilers implement.
Problem
I was pretty sure, that destructors for function's parameters should be called at the exit of corresponding function. Consider 5.2.2p4 of C++11 Standard: [...] The lifetime of a parameter ends when the function in which it is defined returns. [...] However, let's try this code: ``` #include <iostream> using namespace std; struct Logger { Logger(int) { cout << "Construct " << this << '\n'; } Logger(const Logger&) { cout << "Copy construct " << this << '\n'; } ~Logger() { cout << "Destruct " << this << '\n'; } }; int f(Logger) { cout << "Inside f\n"; return 0; } int main() { f(f(f(10))); } ``` After compilation with gcc or clang, the output will be like this: ``` Construct 0x7fffa42d97ff Inside f Construct 0x7fffa42d97fe Inside f Construct 0x7fffa42d97fd Inside f Destruct 0x7fffa42d97fd Destruct 0x7fffa42d97fe Destruct 0x7fffa42d97ff ``` As we can see, all three parameters were destroyed only after the last function call was finished. Is this correct behaviour?