3

The full question fits the title. Here's a quick example:

constexpr int increment(int const value) /*noexcept?*/ {
  return value + 1;
}

As far as I know, noexcept should be interpreted as "nofail" when deciding whether to mark a function with it or not. Therefore, no possible situation for throwing isn't the only reasoning which must be considered.

I'm not using C++20 so my signed overflows aren't defined yet. :)

passing_through
  • 1,778
  • 12
  • 24
  • 3
    The `noexcept` specifier just says that the function won't throw an exception, nothing else. It can still "fail" or have undefined behavior, as long as the mode of failure doesn't throw an exception. – Some programmer dude Apr 26 '20 at 05:43
  • @Someprogrammerdude some resources (including StackOverflow) might disagree with you, I believe. For example: https://stackoverflow.com/questions/20517259/why-vector-access-operators-are-not-specified-as-noexcept. – passing_through Apr 26 '20 at 06:00
  • 1
    From the accepted answer there: "The standard's **policy** on `noexcept` ..." (emphasis mine). It's a *policy* for the standard library, not something that is enforced or have to be blindly followed. – Some programmer dude Apr 26 '20 at 06:05
  • @Someprogrammerdude yes, and the policy seems perfectly reasonable. For example, it allows me to add `if (value == INT_MAX) { throw Smth{}; }` one day. – passing_through Apr 26 '20 at 06:07
  • 2
    Yes, *some day* you might want to add something like that. But until you do, why not mark it as `noexcept`? As mentioned in [one answer](https://stackoverflow.com/a/61436512/440558) it could help the compiler, but it is also part of the interface that other programmers read and deduce information from. If they see that your function is `noexcept` then they can use it in their own `noexcept` functions, or don't worry about exceptions and won't need a `try ... catch` clause for your function. – Some programmer dude Apr 26 '20 at 06:13
  • If you one day want to thrown an exception, you release a new and *well documented* breaking version of your code. – Some programmer dude Apr 26 '20 at 06:13

2 Answers2

4

As far as I know, noexcept should be interpreted as "nofail"

That's not correct. noexcept literally means "I promise this function will never throw an exception." There are myriad other types of failures, such as segmentation faults, illegal instructions, the calling of pure virtual functions, integer divide by zero, not to mention "Bob in accounting told me all our customer numbers consist only of digits, but I just found out our very first customer's ID was actually Q001 and it doesn't parse." None of those will necessarily result in an exception, and neither will signed integer overflow, so functions failing in those ways can still be noexcept even though they can fail--they just can't throw C++ exceptions.

You may then wonder, "What happens if an exception is thrown by a noexcept function?" In that case, std::terminate() will be called, and your program will end.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • However, `std::vector::operator[]` isn't `noexcept` though it never throws. Why? – passing_through Apr 26 '20 at 05:57
  • 2
    @passing_through: Predictably there is an SO question for that: https://stackoverflow.com/questions/20517259/why-vector-access-operators-are-not-specified-as-noexcept – John Zwinck Apr 26 '20 at 06:00
  • Yes, and the opinions there seem contradicting with the one in the answer. – passing_through Apr 26 '20 at 06:01
  • 1
    @passing_through: Perhaps your question is underspecified and/or opinion-based, due to your use of the word "should" and the fact that it's not unclear whether you're asking about common practice in C++ programs vs standard library implementations. – John Zwinck Apr 26 '20 at 06:08
  • `std` can be considered a common practice, can't it? Moreover, it has strong responsibilities so it's reasoning is probably also strong. – passing_through Apr 26 '20 at 06:12
  • 2
    @passing_through: The practices employed when defining the standard library are anything but common. They try hard to avoid making assumptions about how implementors will prefer to do things, what sort of hardware the code will run on, what identifiers may be defined by user code, and so on. Lots of these things are not relevant to most C++ code, because we can (and do) usually make more assumptions that are relevant to our particular application and its deployment. – John Zwinck Apr 26 '20 at 06:19
  • @passing_through: "*std can be considered a common practice, can't it?*" ... no, it can't. Most C++ libraries don't even use the standard library's *naming convention* (everything in snake_case), let alone the specific conventions of how to use language features like `noexcept`. – Nicol Bolas Apr 26 '20 at 06:19
2

noexcept is just your "promise" that the function will never allow an exception escaping from it, and the meaning is that if that instead happens your code will stop right there by calling std::terminate instead of allowing the exception to escape.

Knowing that a function will never throw an exception allows the compiler to generate more efficient/compact code in the caller and allows the creation of more robust software (a software that immediately terminates when something that was not designed to handle happens is more robust that software that instead keeps running doing random things... this is something that many young programmers are confused about).

Exceptions unfortunately are not the only source of failures in C++, where you have the big elephant int the room of "undefined behavior", so writing truly robust software in C++ is an extremely difficult task because you should also avoid every potential undefined behavior (and that's close to impossible to do; for example can generate undefined behavior any integer math operation, any use of iterators, any array access, any pointer access, any uninitialized variable, any multiple unsequenced side effect to the same memory, any race condition... etc. etc.).

Note of course that even a perfectly "safe" low level language that has no undefined behavior but guaranteed runtime errors instead would be no "silver bullet" for writing truly robust software. The reason is that you can have sort of "undefined behavior" at a more logical level if your algorithms do not handle the way you wanted all cases that are presented to them.

In other words there's not much of a difference for the end user if your program does random things because of C++ undefined behavior or because you caught and handled an exception that was not sourcing where you thought it was coming from (what nothrow wants to protect you from) or because your code simply didn't consider and handled that the customer contact data could have and empty phone number.

Undefined behavior concept of course is bad, and is there because allows generation of faster code. In my opinion it is debatable this should be the default in a programming language; other languages preferred a safer default environment and instead allow specifically marked "fast and dangerous" zones where the requirement is that a programmer never makes any low-level mistake.

6502
  • 112,025
  • 15
  • 165
  • 265