Live data from Hacker News

Problems with C++ exceptions

marler8997.github.io

41–50 of 112 posts

Re: Problems with C++ exceptions

#41
All this hassle can be avoided by using `cleanup` compiler attribute.

Manage classical C resources by auto-cleanup variables and do error-handling the normal way. If everything is OK, pass the ownership of these resources from auto-cleanup variables to C++ ctor.

Note this approach plays nicely with C++ exception, and will enter C standard in the form of `defer`.

Re: Problems with C++ exceptions

#42
Or do without exceptions for control flow. For example Elixir does have try/catch but it's used very rarely because most functions return tuples with the first element being either :ok or :error. Then we can pattern match it and return an :error to the caller if we have to, possibly bubbling up several levels return after return. Or let the process crash and restart while the rest of the application keeps running. A surprising number of errors eventually fix themselves (API calls, disk space, missing data) when you design the system to attempt more times to complete its tasks. That's not only a characteristic of Elixir and the BEAM languages. You can do it more or less easily on any language. Maybe you need a queue and workers reading from the queue and all it takes to manage them, and BEAM makes it convenient by including most of it.

The page about try/catch explains it well https://hexdocs.pm/elixir/try-catch-and-rescue.html

Re: Problems with C++ exceptions

#43
post #35

Earlier quoted context omitted.

In high-level code, pretty much everything can fail in many different ways, and usually you're either just passing the error up or handling it in some catchall manner. Rust's behavior makes sense for its use cases, but it'd get exhausting doing this in like a web backend.

It's already too exhausting to use for OOM, which is why Rust effectively punted on that from the very beginning. And the ironic thing is that anyhow::Error (or similar) seems poised to become idiomatic in Rust, which AFAIU always allocates, while the extremely belated try_ APIs... does anybody even use them? It's a shame. Were I designing a "low-level" or "systems" language, rather than put the cart before the horse…

Hm, not sure how you'd do this. OOM error auto bubbling up sounds dangerous because the inner code might not leave things in a consistent state if it exits unexpectedly, so that makes sense to manually handle, but it's tedious. Rust at least has nice ? and ! syntax for errors, unlike Go where the error-prone error handling actually ruins the entire language.

Re: Problems with C++ exceptions

#44
post #35

Earlier quoted context omitted.

In high-level code, pretty much everything can fail in many different ways, and usually you're either just passing the error up or handling it in some catchall manner. Rust's behavior makes sense for its use cases, but it'd get exhausting doing this in like a web backend.

It's already too exhausting to use for OOM, which is why Rust effectively punted on that from the very beginning. And the ironic thing is that anyhow::Error (or similar) seems poised to become idiomatic in Rust, which AFAIU always allocates, while the extremely belated try_ APIs... does anybody even use them? It's a shame. Were I designing a "low-level" or "systems" language, rather than put the cart before the horse…

> while the extremely belated try_ APIs... does anybody even use them?

I want to say the main driver for those right now is Rust for Linux since the "normal" panicking behavior is generally undesirable there.

Re: Problems with C++ exceptions

#45
Or, if you don't want to go to the trouble of writing an RAII wrapper class for FILE*, just use scope_guard and (after determining that fopen() succeeded) register a lambda to close the FILE* on exiting the function (including by throwing an exception). I'm not a huge fan of scope_guard (or defer() in other languages), but it gets the job done for one-off cases.

Re: Problems with C++ exceptions

#46
I think i agree with commenters that article kind-of uses exceptions wrong.

But this shows problems with C++ exceptions, C++ codebases are literred with bad exception usage because "normal" programmers don't get it. Most of didn't get it for long time. So, they are complex enough that their usage is risk.

Anyway, IMO C++ exceptions have two fundametal problems:

* lack of stacktrace, so actually lack of _debugabbility_, that's why people try/catch everything

* destructor problem (that actually there are exceptions tht cannot be propagated further and are lost

Re: Problems with C++ exceptions

#47
post #35

Earlier quoted context omitted.

In high-level code, pretty much everything can fail in many different ways, and usually you're either just passing the error up or handling it in some catchall manner. Rust's behavior makes sense for its use cases, but it'd get exhausting doing this in like a web backend.

It's already too exhausting to use for OOM, which is why Rust effectively punted on that from the very beginning. And the ironic thing is that anyhow::Error (or similar) seems poised to become idiomatic in Rust, which AFAIU always allocates, while the extremely belated try_ APIs... does anybody even use them? It's a shame. Were I designing a "low-level" or "systems" language, rather than put the cart before the horse…

I think Rust's choice to panic on OOM is the right choice for 95% of code people write. It would be absurdly verbose, and OOM can be very tricky to recover from without careful top down design because it's very easy for error handling code to itself try and allocate (print/format a message) leading to a process abort. The mistake was not having the fallible APIs on allocating containers from the start, for the users that do care and can tangibly recover.

Depending on the OS you likely won't even get the chance to handle the error because the allocation never fails, instead you just over commit and kill the process when physical memory gets exhausted.

I guess what I'm trying to say is designing your language's error handling primitives around OOM is probably not a good idea, even in a systems programming language, because it's a very rare class of generally unrecoverable error that only very carefully designed code can recover from.

Anyhow allocating isn't that absurd either. It keeps the size of Result down by limiting the 'E' to be a pointer. Smaller Result can help the compiler generate better code for passing the return value, and the expectation is the error path is rare so the cost of allocating might be outweighed by the lighter Result benefits. Exceptions take a similar standpoint, throwing is very slow but the non-exceptional path can (theoretically) run without any performance cost.

Re: Problems with C++ exceptions

#48
post #8

Earlier quoted context omitted.

That means you cannot use early exit, and all your variables must be checked as to whether they were initialized (which on top of the checks might also require further state).

You can use goto to jump to one of several exit conditions based on the level of cleanup you need. It also nicely unifies all error exits into one place. The kernel makes heavy use of this style.

sure, but that has limitations as well, since gotos can't cross lexical scopes, so you can't introduce variables later on, and it's easy to mess up.

Destructors are a higher-level and safer approach.

Re: Problems with C++ exceptions

#49

Java and Rust are the only language that I know of that has proper handling of exceptions; mandatory declaration as part of method declaration, since exceptions ARE an integral part of the contract. (Yes, I consider the Result being corresponding to exception declaration, since the return value MUST be checked prior to use of T.)

In fairness, Rust also has unchecked exceptions (panics, if you use panic-unwind).

Java too has unchecked exceptions, though the post praising "mandatory declaration" didn't mention it for either.

But they CAN be caught with a standard catch which may be non-intuitive if you don't know about them, and about that, in advance.

Re: Problems with C++ exceptions

#50
post #38
post #6

Author completely misunderstands how to use exceptions and is just bashing them. A lot of what he says is inaccurate if not outwardly incorrect. Also Bjarne's control of C++ is quite limited, and he is semi-retired, so asking him to "fix his language" is fairly misguided. It's designed by a committee of 200+ people. Anyway what you want seems to be to not use exceptions, but monads instead. These are also part of the…

> Author completely misunderstands how to use exceptions and is just bashing them. A lot of what he says is inaccurate if not outwardly incorrect. Do you mind to elaborate what you believe are the misunderstandings? Examples of incorrect/inaccurate statements and/or an article with better explanations of mentioned use cases would be helpful. > it's called std::expected How does std::expected play together with all ot…

Well, he's using try/catch locally. You're not supposed to handle errors locally with exceptions. The whole point is inversion of control, you manage them at the point where you can do meaningful recovery, which then triggers the cleanup of the whole stack of frames once the exception bubbles up, rather than systematically cleaning up on the normal control flow path.

Regardless, in his example, he could achieve what he wants by wrapping the try in a lambda, and returning either the value from try or nullopt from catch. But clearly, that's just converting exceptions to another error-handling mechanism because he isn't doing it right.

He claimed that not handling an exception causes the program to crash, that's just plain incorrect. To be fair many people use the term "crash" liberally.

std::expected or equivalent is often used with std::error_code, which is an extensible system (error codes are arranged in categories) that among others interops with errno.

Post reply on HN