Live data from Hacker News

Problems with C++ exceptions

marler8997.github.io

11–20 of 112 posts

Re: Problems with C++ exceptions

#11
post #7

This is a common problem with try-catch syntax. An alternative, and arguably more useful syntax would be try (File_handle fh {s, "r"}) { // use fh } unless (const File_error& e) { // handle error } Where the "use fh" part is not covered by the exception handler. This is covered (in ML context) in https://www.microsoft.com/en-us/research/publication/excepti...

Don't use try/catch in the first place; that's where his error lies.

Re: Problems with C++ exceptions

#12
post #3

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.)

Swift user here: I have to say one of the best features of Swift is the exception handling. Which is to say, exceptions in Swift are not C++/Java/Obj-C style exceptions, but instead are a way to return an error result from a function. And Swift enforces that the error is handled. That is, a `throw` statement in Swift simply returns an `Error` value to the caller via a special return path instead of the normal result.…

From what I can read Swift gives you a stack trace which is good. At the moment I’m using Go where that stack is only generated where the panic is triggered, which could be much higher up. Makes it a lot more unwieldy to figure out where an error happens because everyone uses:

> if err != nil return err

Re: Problems with C++ exceptions

#13

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.)

`Result` comes from Haskell's `Either a b` type. F# also has a `Result` type.

It's funny how often functional programming languages lead the way, but imperative languages end up with the credit.

Re: Problems with C++ exceptions

#14

Honestly, I thought the diatribe would focus on needless complexity. The starting example is how I'd do it in C: ``` void f(const char* p) // unsafe, naive use { FILE \*f = fopen(p, "r"); // acquire // use f fclose(f); // release } ``` Wouldn't the simpler solution be ensuring your function doesn't exit before release? All that c++ destroyer stuff appears somewhat unnecessary and as the author points out, creates eve…

In C, you're correct. The problem is that, in C++, one must account for the fact that anything could throw an exception. If something throws an exception between the time that f is opened and f is closed, the file handle is leaked. This is the "unsafe" that Bjarne is talking about here. Specifically, exception unsafety that can leak resources.

As an aside, it is one of the reasons why I finally decided to let go of C++ after 20 years of use. It was just too difficult to teach developers all of the corner cases. Instead, I retooled my system programming around C with model checking to enforce resource management and function contracts. The code can be read just like this example and I can have guaranteed resource management that is enforced at build time by checking function contracts.

Re: Problems with C++ exceptions

#15
>The first is that our error message may not be correct. It’s possible that the exception we’ve caught was not introduced by opening this file, and, the errno may not reflect the errno at the time fopen was called.

All that is needed is a better File_error type that includes the error that happened.

  void f(string s)
  {
      try {
          File_handle fh { s, "r"};
          // use fh
      } catch (const File_error& e) {
          fprintf(stderr, "File error: %s\n", e.msg.c_str();
          return;
      }
  }

Re: Problems with C++ exceptions

#16
post #10
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…

Agreed. Author is trying to mix paradigms. Simplest approach if they want local handling and non-propagation of errors is to just have the file holder not check for open success, and check that manually after construction. Then you get guaranteed closure of file no matter how the function is exited. class File_handle { FILE *p; public: File_handle(const char *pp, const char *r) { p = fopen(pp, r); } ~File_handle() {…

this may lose the value of errno, right?

Re: Problems with C++ exceptions

#17
The first two problems can be solved in a straightforward way with more custom exception types. For the "bigger problem", catch(...) can be used to prevent your code from crashing. If you really want to handle each case explicitly you could also use enums in combination with compiler flags that enable exhaustive checking.

Re: Problems with C++ exceptions

#18

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).

Re: Problems with C++ exceptions

#19
post #16
post #10

Earlier quoted context omitted.

Agreed. Author is trying to mix paradigms. Simplest approach if they want local handling and non-propagation of errors is to just have the file holder not check for open success, and check that manually after construction. Then you get guaranteed closure of file no matter how the function is exited. class File_handle { FILE *p; public: File_handle(const char *pp, const char *r) { p = fopen(pp, r); } ~File_handle() {…

this may lose the value of errno, right?

Yes, it would. It would be trivial to add errno as an instance variable for File_Handle class though.

Re: Problems with C++ exceptions

#20
post #8

Honestly, I thought the diatribe would focus on needless complexity. The starting example is how I'd do it in C: ``` void f(const char* p) // unsafe, naive use { FILE \*f = fopen(p, "r"); // acquire // use f fclose(f); // release } ``` Wouldn't the simpler solution be ensuring your function doesn't exit before release? All that c++ destroyer stuff appears somewhat unnecessary and as the author points out, creates eve…

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.
Post reply on HN