2

I'm making a small error handling system and I want to do a fatal error that terminate the program. I have thought of two way to do that:

[[noreturn]] inline void fatal_error1(char const* msg) {
    std::terminate();
}

[[noreturn]] inline void fatal_error2(char const* msg) noexcept {
    throw std::runtime_error{msg};
}

Is there a reason why using fatal_error2 would not be recommended? The goal of the function is to terminate the program and I even marked it as noreturn, but everyone seems to tell me to not throw in noexcept functions.

I am tempted to use the fatal_error2 because it output what() in the terminal, whereas I would need to include some output function in that header to print the message in fatal_error1.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • 1
    Is there something wrong with the `std::terminate()` approach? If not why are you looking for alternatives? – Borgleader Oct 10 '17 at 14:04
  • 2
    The second approach is not recommended, because it's the same as the first, but not in an obvious way. – StoryTeller - Unslander Monica Oct 10 '17 at 14:07
  • @Borgleader well... In the first version, I'd have to include `iostream` to output an error, whereas the exception version output `what()` in most system. It might not be the best reasons to pick `fatal_error2`, but that error handling function will pretty much be used in a lot of places in my program, and I don't quite want to include `iostream` everywhere, or even `stdio`. – Guillaume Racicot Oct 10 '17 at 14:07
  • 1
    Why would you need to include `iostream`, or any other I/O-related header, everywhere? – molbdnilo Oct 10 '17 at 14:09
  • @molbdnilo including header is transitive. If I include `fatal.h`, and that file includes `iostream`, I effetively included iostreams everywhere. – Guillaume Racicot Oct 10 '17 at 14:11
  • @GuillaumeRacicot I'm confused, why does fatal_error1 require any io headers at all? You might need them in the cpp file, but the header doesn't need them at all. – UKMonkey Oct 10 '17 at 14:15
  • @UKMonkey - I assume the idea is to provide this very inlinable function in a header (though it's missing an `inline` specifier to avoid ODR issues). – StoryTeller - Unslander Monica Oct 10 '17 at 14:16
  • @UKMonkey my apologies. That function is in the header in my code because it is templated in my code. I'll edit the question. – Guillaume Racicot Oct 10 '17 at 14:17
  • @GuillaumeRacicot So what you're saying is - you'd rather throw in a no throw function, and have a handler somewhere that will have to catch and then work out what to do with an exception that you promised wouldn't exist; and do this in every program that's going to use your header; than to include iostream in your header and get the error handling done in a consistant way for everything that uses it - for the sake of compilation time? – UKMonkey Oct 10 '17 at 14:20
  • @UKMonkey I'm only curious about the pros and cons of both things. I wouldn't ask the question if I knew all of them! Also, I don't want the whole program unwind or risk that someone use `catch(...)` somewhere, so I thought to use noexcept in that case. – Guillaume Racicot Oct 10 '17 at 14:24

2 Answers2

8

Is there a reason why using fatal_error2 would not be recommended?

If you would like to call std::terminate - just do that. This is the best practice because it follows the principle of least surprise.

fatal_error2 is declared as noexcept but it throws an exception, which makes the reader of the code doubt the intentions of the author.


I am tempted to use the fatal_error2 because it output what() in the terminal...

This does not seem to be a good excuse because:

  1. This functionality is not portable and not required by the C++ standard.
  2. You can do that yourself portably with std::cerr << msg << std::endl or fprintf(stderr, ...). And, again, this makes your intention clear to the reader of the code.
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
1

Yes, it's okay.

The end result is that you are enforcing that you have an unhandled exception. (an unhandled exception is the same as throwing an exception from a noexcept scope)

This is the same as if there were no catch blocks that could catch the exception you threw. Like you mentioned in your post, you may get some information about the uncaught exception when the program terminates, which could be useful.

Some may say that it's better to write to std::err and then call std::terminate. I won't argue against it, but it does require a #include <iostream>. Whether that's better than requiring a #include <stdexcept> is your call.

AndyG
  • 39,700
  • 8
  • 109
  • 143
  • Putting it that way, I still have to include something, which defeated my initial motivation. However, having the same behavior as an uncaught exception makes it *very* appealing. Not only for the output, but for debugging too. – Guillaume Racicot Oct 10 '17 at 14:41