top | item 27597783

(no title)

TwoBit | 4 years ago

> Is now impossible

I don't see how that is so. C++ 17 allows new Widget to complete and then the priority() call to execute and throw before both are passed to shared_ptr(), thus creating a leak. Your cited example [1] doesn't leak because both arguments are shared_ptr. Seems to me that C++ 17 does indeed solve this latter case but not the former.

discuss

order

dvt|4 years ago

Per [1]:

> evaluations of A and B are indeterminately sequenced: they may be performed in any order but may not overlap: either A will be complete before B, or B will be complete before A. The order may be the opposite the next time the same expression is evaluated.

And:

> 21) Every expression in a comma-separated list of expressions in a parenthesized initializer is evaluated as if for a function call (indeterminately-sequenced)

Emphasis mine. What the above basically says is that in the case of some function `f(A, B)`, the arguments `A`, and `B`, are what's known as "indeterminately-sequenced" -- this mean that their execution cannot be interleaved (overlap) -- but they still individually execute in a non-deterministic order (A before B, and sometimes B before A)!

With that said, the good news is that B can now never throw in the middle of A, which is precisely what we have in OP's example.

[1] https://en.cppreference.com/w/cpp/language/eval_order

_huayra_|4 years ago

Whew thanks for looking this up! I was afraid I'd have to add yet another entry to my gigantic C++ footguns.org document. It's getting so big now that Emacs struggles a bit to load it due to inline code examples!

nyanpasu64|4 years ago

> both are passed to shared_ptr()

priority() is not passed to shared_ptr(), only to processWidget().

TwoBit|4 years ago

OK, I must have mistaken what the original was, because I thought it was like this:

processWidget(new Widget, priority());

I think I saw the above code elsewhere.

ronyclau|4 years ago

IIRC, this may also leak when `priority()` throws due to evaluation order. (Not exactly sure now, as I now always use `make_shared` whenever possible.)

However in the Effective C++ example, the `shared_ptr` constructor gave a false sense of security as it seemed the `new`-ed `Widget` was always managed by the smart pointer from its allocation.