Hacker News new | ask | show | jobs
by TwoBit 1820 days 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.

3 comments

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

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!
At first I thought that was a domain and not an org file. :)

Looks like footguns.com is taken but footguns.org is still available.

Gotta register a 501c3 to help save poor C++ programmers from the many footguns. Donate today!
Your footguns.org file legitimately sounds like something that other C++ programmers would find useful. I for one, being a rank novice at the language (despite attempting to use it for the last ten years!), would certainly appreciate a reference like that.
Most of it is basically from cppcon talks and Scott Meyer's books, but the advice I basically give to incoming C++ programmers today is this:

* Start with C++20 unless you have a very good reason not to. Not only does it obviate crufty old things like SFINAE (concepts!), but it includes a ton of usability fixes (e.g. reflexive operator== -> I only have to write the code for MyType == MyOtherType in order to get both that version and MyOtherType == MyType). A lot of lambda behavior has really been cleaned up too (e.g. capturing `this` has fewer corner cases).

* start with Google's coding guidelines [0], as they've been developed to avoid many footguns (the bottom line depends on it). Once you understand things better, keep removing these rules (e.g. about exceptions, const& parameters; many of these rules are good for big teams, but annoying to follow for individuals)

* The CppCon "back to basics" talks are absolute goldmines, and the speakers usually tell you if some technique has been outdated as of the recording. Some things in certain books, although valuable, may be outdated based on later revisions to the language.

* The best notes to take are usually some structure list followed by a bunch of godbolt links with examples, e.g. this one I made to demonstrate the reflexive operator== behavior [1]

[0] https://google.github.io/styleguide/cppguide.html [1] https://godbolt.org/z/scPdcaWT7

I will do that when I am done reading Java Puzzles and JavaScript the Good Parts.
> both are passed to shared_ptr()

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

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.

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.