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.
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:
"Indeterminately sequenced" is defined as:
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.