Search code examples
c++c++17undefined-behaviorexception-safety

Is this item from Effective Modern C++ still up to date?


p.146 of effective modern C++ :

void processWidget(std::shared_ptr<Widget> spw, int priority);
void cusDel(Widget *ptr);//a custom deleter

This was an unsafe call prior to C++17 :

processWidget(std::shared_ptr<Wdiget>(new Widget, cusDel), computePriority());

It used to be unsafe because computePriority could be called after new Widget but before std::share_ptr constructor and if computePriority yielded an exception, the dynamically allcoated Widget would be leaked. Therefore you could do this :

std::shared_ptr<Widget> spw(new Widget, cusDel);
processWidget(spw, computePriority());

Now this would add a copy constructor operation on shared_ptr. So you could also do this :

std::shared_ptr<Widget> spw(new Widget, cusDel);
processWidget(std::move(spw), computePriority());

So my question is, is the following code still able to leak memory in C++17?

processWidget(std::shared_ptr<Wdiget>(new Widget, cusDel), computePriority());

I've read this and this but I'm still unsure, I believe that std::shared_ptr<Wdiget>(new Widget, cusDel) and computePriority() are both sequenced before the call to processWidget, however I think computePriority() can still throw an exception after new and before shared_ptr takes ownership of the newly created object.


Solution

  • C++17 did change the sequencing with regard to the evaluation of the expressions used to call a function. While it doesn't impose any particular order, it does say:

    The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter.

    "Indeterminately sequenced" is defined as:

    Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which.

    So one parameter will be initialized before the other, including all side-effects. So either the first argument or the second argument is fully evaluated before the other.