1

If we implement the following function:

template <typename... Ts>
[[noreturn]] inline bool die(std::string_view message_format = "", Ts&&... args);

We can then write:

if (bad_thing_happened()) die("A bad thing happened!");

or, for example

things_are_ok() or die("Things are not ok, and foo is {}", foo);

I know this idiom from perl (which also has unless, making such expressions more natural-language like: die("oh no") unless (things_are_ok())). Is it a good idea to use this idiom in C++?

Note: I'm only asking about code where it makes sense to terminate the application. If std::exit() is inappropriate, naturally so is a die() command.

20
  • 2
    As I understand the rationale behind die, programming languages like Perl and PHP create individual web pages by running a script in a process. Writing die essentially means "The web page has been sufficiently rendered, I no longer have any use for you, script." It's hard to imagine there being much benefit to such a mechanism in C++ when C++ is not commonly used to build web pages, especially when so much attention is paid to managing memory gracefully in C++. Commented Jun 27, 2022 at 18:13
  • 2
    @RobertHarvey: die() predates the WWW... it's not an HTTP-specific or even networking-specific construct. die() is for a process on a Unix-like system.
    – einpoklum
    Commented Jun 27, 2022 at 18:45
  • 1
    @RobertHarvey: So, why is this hard to imagine? Isn't it the same rationale as exit(), terminate() and abort()?
    – einpoklum
    Commented Jun 27, 2022 at 19:12
  • 3
    This question is being discussed on meta. Commented Jun 28, 2022 at 17:57
  • 1
    By any chance, are you a German speaker and are you referring to this? relevant link
    – Flater
    Commented Jul 20, 2022 at 9:58

3 Answers 3

4

I can imagine two implementations of die, and I have issue with both of them

template <typename... Ts>
[[noreturn]] inline bool die(std::string_view message_format = "", Ts&&... args)
{
    std::cerr << std::vformat(message_format, std::make_format_args(args...));
    std::abort(); // or std::exit or std::terminate
}

That is, write the message somewhere and end the program. I could imagine a project using this, but not the projects I'm involved in.

It seems most appropriate in projects large enough that you don't just return up to main, but small enough that killing the whole process is never overkill.

template <typename... Ts>
[[noreturn]] inline bool die(std::string_view message_format = "", Ts&&... args)
{
    throw std::runtime_error(std::vformat(message_format, std::make_format_args(args...)));
}

I.e. throw a generic exception, with the message. I would prefer some granularity in the type of the exception, so that args... could instead be a data member for the catch. If pressed, i'd write that as

template<typename T, typename... Args>
[[noreturn]] inline bool die_with(Args&&... args)
{
    throw T(std::forward<Args>(args)...);
}

things_are_ok() or die_with<things_exception>("things not ok", foo);

But there are other ways of massaging a throw to be a bool expression

things_are_ok() or (throw things_exception("things not ok", foo), false);
7
  • I was thinking more along the lines of the first version, although with std::exit(). An exception might be caught, and I want die() to actually do what it says. But thanks for emphasizing this point.
    – einpoklum
    Commented Jun 27, 2022 at 10:24
  • @einpoklum std::abort, std::exit or std::terminate would be interchangeable for the purpose of this answer
    – Caleth
    Commented Jun 27, 2022 at 10:25
  • Fair enough, edited that in.
    – einpoklum
    Commented Jun 27, 2022 at 10:26
  • Your second die just obfuscates throw things_exception("things not ok", foo);, and is thus a net drain. (Though it can be used as a callback, and try itself cannot.) Also, good on you to fix the format-strings type. Commented Jun 27, 2022 at 10:40
  • @Deduplicator it's a bool expression, rather than a throw expression. You could do similar with throw blah... , false
    – Caleth
    Commented Jun 27, 2022 at 10:52
1

Is it a good idea to use this idiom in C++?

No.

Exit (or terminate, or abort, or die) is not something you should use in C++. There are cases when it is useful, but those are special cases (special as in "we are working at a nuclear power plant and need to guarantee the application is exited NOW - as in RIGHT NOW DAMMIT!").

To interrupt process flow in a normal application, it is better to throw an exception.

3
  • 1. Why is it "better" to exit using an exception?. 2. In many scenarios, use of exceptions is unacceptable. 3. Sometimes you need to exit while handling an exception.
    – einpoklum
    Commented Aug 26, 2022 at 10:09
  • 1. because there are situations when you decide to interupt your application flow (exit) but client code may decide to handle the error. Exitting does not allow for that option. 2. I have worked in a few projects like that (not using exceptions because they were unacceptable) - the reasoning for not using exceptions was always bogus (the arguments were superficial). 3. If you need to exit while handling the exception, that should be decided while handling the exception, not while raising the exception. Many places that signal an error condition do not know how to handle the error themselves.
    – utnapistim
    Commented Aug 26, 2022 at 11:50
  • 1. I'm not sure what you mean by "client code". If you mean when writing a library, then I certainly agree, but otherwise - I'm the "client". 2. The reasoning for using exception is not "always bogus"; often, it's not even possible, and there are no stack, no interrupt, etc. 3. So, assume my question is about code in an exception handler.
    – einpoklum
    Commented Aug 26, 2022 at 13:40
1

In library code, no. Library code should cause the application to terminate only on the most severe logic errors, something that should never happen (like memory self-corrupting). And if you do this termination, you should at least leave behind a core dump. Even then, throwing an exception specifically designed for severe logic errors wouldn't be a bad idea though, because an unhandled exception will anyway terminate the application, and presumably that exception wouldn't be handled anyway (if bits are flipping randomly, there's no sane way to handle the exception -- on the other hand, if bits are flipping randomly it could be that some exception handler flipped randomly to handle your severe logic error -- but there's also the problem that if bits are flipping randomly, you can't trust your core dump).

However, in application code, only the application author knows. In complex applications, where lot of the code is actually per-application library code, you should probably consider that code similar to generic library code. However, in simple <1000-liner applications it's possible that your error handling strategy is simply exiting. And even if that strategy changes at some point of time, you shouldn't have too much code to rewrite. In any case, some "die" function is far better choice than printing and error message and exiting, because you can easily search for all users of "die" and change them to throw an exception instead -- or maybe you want to just edit the "die" function to throw an exception.

1
  • In library code, I wouldn't exit anyway. Let me clarify this in the question.
    – einpoklum
    Commented Aug 26, 2022 at 20:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.