If some function f
with parameters p_1
, ..., p_n
of types T_1
, ..., T_n
respectively is called with arguments a_1
, ..., a_n
and its body throws an exception, finishes or returns, in what order are the arguments destroyed and why? Please provide a reference to the standard, if possible.
EDIT: I actually wanted to ask about function "parameters", but as T.C. and Columbo managed to clear my confusion, I'm leaving this question be about the arguments and asked a new separate question about the parameters. See the comments on this question for the distinction.
The order in which the arguments to a function are evaluated is not specified by the standard. From the C++11 Standard (online draft):
5.2.2 Function call
8 [ Note: The evaluations of the postfix expression and of the argument expressions are all unsequenced relative to one another. All side effects of argument expression evaluations are sequenced before the function is entered (see 1.9). —end note ]
Hence, it is entirely up to an implementation to decide in what order to evaluate the arguments to a function. This, in turn, implies that the order of construction of the arguments is also implementation dependent.
A sensible implementation would destroy the objects in the reverse order of their construction.
I did not manage to find the answer in the standard, but I was able to test this on 3 most popular C++ compliant compilers. The answer of R Sahu pretty much explains that it is implementation defined.
§5.2.2/8: The evaluations of the postfix expression and of the arguments are all unsequenced relative to one another. All side effects of argument evaluations are sequenced before the function is entered.
Visual Studio C++ Compiler (Windows) and gcc (Debian)
Arguments are constructed in order reverse to their declaration and destroyed in reversed order (thus destroyed in order of delcaration):
2
1
-1
-2
Clang (FreeBSD)
Arguments are constructed in order of their declaration and destroyed in reversed order:
1
2
-2
-1
All compilers were instructed to treat the source code as C++11 and I used the following snippet to demonstrate the situation:
struct A
{
A(int) { std::cout << "1" << std::endl; }
~A() { std::cout << "-1" << std::endl; }
};
struct B
{
B(double) { std::cout << "2" << std::endl; }
~B() { std::cout << "-2" << std::endl; }
};
void f(A, B) { }
int main()
{
f(4, 5.);
}
In §5.2.2[4] N3337 is quite explicit on what happens (online draft):
During the initialization of a parameter, an implementation may avoid the construction of extra temporaries by combining the conversions on the associated argument and/or the construction of temporaries with the initialization of the parameter (see 12.2). The lifetime of a parameter ends when the function in which it is defined returns.
So for example in
f(g(h()));
the return value from the call h()
is a temporary that will be destroyed at the end of the full expression. However the compiler is allowed to avoid this temporary and directly initialize with its value the parameter of g()
. In this case the return value will be destroyed once g()
returns (i.e. BEFORE calling f()
).
If I understood correctly what is stated in the standard however it's not permitted to have the value returned from h()
to survive to the end of the full expression unless a copy is made (the parameter) and this copy is destroyed once g()
returns.
The two scenarios are:
h
return value is used to directly initializeg
parameter. This object is destroyed wheng
returns and before callingf
.h
return value is a temporary. A copy is made to initializeg
parameter and it is destroyed wheng
returns. The original temporary is destroyed at the end of the full expression instead.
I don't know if implementations are following the rules on this.
来源:https://stackoverflow.com/questions/36992039/what-is-the-order-of-destruction-of-function-arguments