32

I saw that C++ 11 added the noexcept keyword. But I don't really understand why is it useful.

If the function throws when it's not supposed to throw - why would I want the program to crash?

So when should I use it?

Also, how will it work along with compiling with /Eha and using _set_se_translator? This means that any line of code can throw c++ exception - because it might throw a SEH exception (Because of accessing protected memory) and it will be translated to c++ exception.

What will happen then?

Nerdroid
  • 13,398
  • 5
  • 58
  • 69
user972014
  • 3,296
  • 6
  • 49
  • 89
  • 1
    You want `noexcept` to tell the system that a function does not throw exceptions. If it still does (because some developer is an idiot and either directly throws an exception, or indirectly calls something without a `try`-`catch` block around it, most likely), then what do you think the system should do? Obviously, if you access memory you are not allowed to access, your code will, in one way or another, crash, so what difference does it make if it crashes one way or another way? – Mats Petersson Dec 07 '14 at 19:22
  • I recommend these posts: https://akrzemi1.wordpress.com/2011/06/10/using-noexcept/ https://akrzemi1.wordpress.com/2014/04/24/noexcept-what-for/ – Andrzej Dec 12 '14 at 13:46
  • Does the program even crash? I was under the impression that `std::terminate` is being called which is much more like an "orderly abort" than a crash (and it basically means that extra code which calls `terminate` needs to be generated, too). – Damon Jan 02 '15 at 11:07
  • https://blog.quasardb.net/when-noexcept-2/ – user972014 Dec 16 '16 at 10:16

2 Answers2

41

The primary use of noexcept is for generic algorithms, e.g., when resizing a std::vector<T>: for an efficient algorithm moving elements it is necessary to know ahead of time that none of the moves will throw. If moving elements might throw, elements need to be copied instead. Using the noexcept(expr) operator the library implementation can determine whether a particular operation may throw. The property of operations not throwing becomes part of the contract: if that contract is violated, all bets are off and there may be no way to recover a valid state. Bailing out before causing more damage is the natural choice.

To propagate knowledge about noexcept operations do not throw it is also necessary to declare functions as such. To this end, you'd use noexcept, throw(), or noexcept(expr) with a constant expression. The form using an expression is necessary when implementing a generic data structure: with the expression it can be determined whether any of the type dependent operations may throw an exception.

For example, std::swap() is declared something like this:

template <typename T>
void swap(T& o1, T& o2) noexcept(noexcept(T(std::move(o1)) &&
                        noexcept(o1 = std::move(o2)));

Based on noexcept(swap(a, b)) the library can then choose differently efficient implementations of certain operations: if it can just swap() without risking an exception it may temporarily violate invariants and recover them later. If an exception might be thrown the library may instead need to copy objects rather than moving them around.

It is unlikely that the standard C++ library implementation will depend on many operations to be noexcept(true). The probably the operations it will check are mainly those involved in moving objects around, i.e.:

  1. The destructor of a class (note that destructors are by default noexcept(true) even without any declaration; if you have destructor which may throw, you need to declare it as such, e.g.: T::~T() noexcept(false)).
  2. The move operators, i.e. move construction (T::T(T&&)) and move assignment (T::operator=(T&&)).
  3. The type's swap() operations (swap(T&, T&) and possibly the member version T::swap(T&)).

If any of these operations deviates from the default you should declare it correspondingly to get the most efficient implementation. The generated versions of these operations declare whether they are throwing exceptions based on the respective operations used for members and bases.

Although I can imagine that some operations may be added in the future or by some specific libraries, I would probably not declaration operations as noexcept for now. If other functions emerge which make a difference being noexcept they can be declared (and possible changed as necessary) in the future.

Johann Gerell
  • 24,991
  • 10
  • 72
  • 122
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
4

The reason that the program may crash is because noexcept tells the optimizer your code won't throw. If it does - well, there's no way to predict what will happen with optimized code.

As for MSVC++, you'd have to check what happens when they implement noexcept. From a Standard viewpoint, SEH is undefined behavior. Accessing protected memory can already crash right now.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 1
    Out of curiosity: what makes SEH undefined behavior? – MFH Dec 11 '14 at 19:48
  • 2
    @MFH: Simply put, SEH does not appear in the Standard, and thus all defined behavior is not SEH. By negation, all SEH is not defined behavior. – MSalters Dec 11 '14 at 22:52
  • Wouldn't that interpretation of UB render anything not explicitly in the standard - e.g. every function, type, namespace one writes - UB? True if you throw from noexcept you enter UB-land, but SEH on its own doesn't necessarily sound like UB by default to me… – MFH Dec 11 '14 at 23:01
  • 1
    @MFH: The standard lays down rules. Those rules do allow `struct foo { int i_34568790845609; }` even though that particular construct does not appear. However, there's just no way that those rules allow SEH. The mere fact that a set of constructs is infinite doesn't mean that it contains everything. The set of even numbers if infinite but does not contain 3. – MSalters Dec 11 '14 at 23:04
  • 1
    @MSaltes: Nothing I don't agree on, but what rule in the standard renders »the implementation specific nature« of SEH - note that SEH does not necessarily result from UB, but can also be issued by software (e.g. in the case of invalid parameters). SEHs appear to be analogous to posix-signals in that regard, which would then also be UB… – MFH Dec 11 '14 at 23:14
  • @MFH: One important thing to understand about POSIX signals is that `signal()` is in fact C. The fundamental mechanism isn't foreign. That said, I'm not familiar enough with POSIX signals to rule they're UB. As for the UB part of SEH, observe that any defined behavior differs from SEH. C++ exceptions naturally come closest, but a SE is fundamentally not a C++ exception. – MSalters Dec 11 '14 at 23:21
  • @MFH: Until a few years ago, Undefined Behavior meant nothing more nor less than that the C standard did not in and of itself impose any requirements about what an implementation would do. It was extremely common for compilers and platforms to promise what would happen in some such situations, and it was perfectly respectable for code to written for a particular platform to rely upon promises made thereby. Lately, however, a philosophy has emerged that a compiler is entitled to assume that a program will never enter any state that would make Undefined Behavior inevitable. – supercat Apr 21 '15 at 22:45