In cppref, the following holds until C++17:
code such as
f(std::shared_ptr<int>(new int(42)), g())
can cause a memory leak ifg
gets called afternew int(42)
and throws an exception, whilef(std::make_shared<int>(42), g())
is safe, since two function calls are never interleaved.
I'm wondering which change introduced in C++17 renders this no longer applicable.
The evaluation order of function arguments are changed by P0400R0.
Before the change, evaluation of function arguments are unsequenced relative to one another. This means evaluation of g()
may be inserted into the evaluation of std::shared_ptr<int>(new int(42))
, which causes the situation described in your quoted context.
After the change, evaluation of function arguments are indeterminately sequenced with no interleaving, which means all side effects of std::shared_ptr<int>(new int(42))
take place either before or after those of g()
. Now consider the case where g()
may throw.
If all side effects of
std::shared_ptr<int>(new int(42))
take place before those ofg()
, the memory allocated will be deallocated by the destructor ofstd::shared_ptr<int>
.If all side effects of
std::shared_ptr<int>(new int(42))
take place after those ofg()
, there is even no memory allocation.
In either case, there is no memory leak again anyway.
The P0145R3 paper (which was accepted into C++17) refines the order of evaluation of several C++ constructs, including
Postfix expressions are evaluated from left to right. This includes functions calls and member selection expressions
Specifically, the paper adds the following text to 5.2.2/4 paragraph of the standard:
The postfix-expression is sequenced before each expression in the expression-list and any default argument. Every value computation and side effect associated with the initialization of a parameter, and the initialization itself, is sequenced before every value computation and side effect associated with the initialization of any subsequent parameter.
来源:https://stackoverflow.com/questions/48842397/stdmake-shared-change-in-c17