4

I began adding noexcept to my code, but I'm wondering if it's even wise to bother adding it to inline functions. I'm assuming the optimizer would omit the runtime check when it's clearly unneeded... but from a human/style perspective, is it worth adding noexcept to trivial functions like getters, settings, increment functions, etc? I'm thinking it's visual clutter for something totally obvious. I'm debating a rule that inline functions get to omit noexcept, but normal .hpp/.cpp functions have to have it if they don't throw.

Secondly, I have a large amount of code that can't throw at all because it has no allocations (in my chess engine), that includes no STL or anything else that might fail, so success is always guaranteed. Wouldn't noexcept slow it down due to the runtime check? Does anyone use a macro to switch between using noexcept for DEBUG builds, but swap to throw() for release, which is compile-time only?

VoidStar
  • 5,241
  • 1
  • 31
  • 45
  • 2
    `code that can't throw at all because it has no allocations` How are allocations the only exception reason? – deviantfan Aug 05 '15 at 07:50
  • 2
    What "runtime check"? – Chris Drew Aug 05 '15 at 08:10
  • This might be helpful: [Should I use noexcept for getters always?](http://stackoverflow.com/q/21330807/3425536) – Emil Laine Aug 05 '15 at 08:21
  • @deviantfan: Well, no OS calls, no allocations... it's a library with no functions that can fail in any way. it's chess calculations. Perfectly reasonable for a calculation library imo. – VoidStar Aug 05 '15 at 08:22
  • @Chris Drew: `std::terminate` must be called at runtime if the `noexcept` specification is violated. This requires setting up an exception handler to catch it at runtime. I expect this to be pretty minimal on amd64 but on x86, the unwinding is a little bit more effort, at least that's my understanding. – VoidStar Aug 05 '15 at 08:24
  • Why would you do this? Isn't it just checking if the function may throw an exception? I doubt it will do any good or any harm to performance at all, as it is checked at compilation. Thus, unnecessary code. – Leśny Rumcajs Aug 05 '15 at 08:24
  • 1
    `noexcept` functions don't need to be unwound and therefore don't need to be kept in an unwindable state. That's the optimization opportunity. – Emil Laine Aug 05 '15 at 08:31
  • @zenith: That's true for throw() [edit: only VC++ does this for `throw()`]. However, `throw()` is compile-time only, whereas noexcept is not. The standard requires that violations of `noexcept` be detected at runtime and `std::terminate` be invoked. I'm not sure how much unwinding can actually be skipped since the compiler is in effect catching the illegally thrown exception in order to call `std::terminate`. The exact runtime performance ramifications of this is something I'd like insight into. – VoidStar Aug 05 '15 at 09:00
  • `noexcept` was carefully specified to be zero overhead on reasonable* implementations. AFAIU all implementations exploit these optimization opportunities _(*all major platforms ABI's except for Windows 32-bit are considered reasonable in this regard)_ – Fabio Fracassi Aug 06 '15 at 09:42
  • @tuple_cat I could not understand what actually is unwindable state because every function any way maintains runtime stack and if function is noexcept then program will terminate else stack will be unwinded – PapaDiHatti Apr 29 '17 at 14:01

2 Answers2

4

If your inline function is a leaf-level function, i.e. It calls no functions itself, then in theory a compiler could determine that it won't throw and omit whatever exception handling may have been generated otherwise. So performance-wise, it may prove unnecessary.

Having said that, you shouldn't expect to see a performance reduction from adding noexcept. Whatever code that would have to have been generated to handle propagation of exceptions shouldn't become any more complicated by adding noexcept. It's worth noting that a compiler is permitted to omit unwinding the stack entirely if an exception is thrown from a noexcept function. This is largely where the direct benefits of noexcept come from.

As for a style recommendation, first and foremost, consider whether noexcept would be a useful part of your interface. Things such as move operations can benefit greatly from being noexcept for algorithmic reasons, but besides those, it's really up to you to decide where noexcept has value for you, your interface and the users of your interface.

If this doesn't answer your question, feel free to comment on my answer and I will clarify further.

Sidenote: throw(), as well being deprecated in C++11, doesn't give the same guarantees as noexcept. If an exception is thrown through a function declared throw(), the stack must be completely unwound up to the caller of that function. See 15.5.2.1 in version N3337 of the C++ standard for reference to this behaviour.

Jared Mulconry
  • 479
  • 3
  • 8
  • I guess VC++ violates the standard then, it has always optimized based on `throw()`. See https://msdn.microsoft.com/en-us/library/wfa0edys.aspx . Also, you haven't addressed the potential cost of dealing with runtime violations of noexcept. I'm still thinking that individual compilers are likely to end up providing a way for "compile-time-only" version of `noexcept`, like VC++ already does, so a macro would be the best way to tune the code base to each compiler. – VoidStar Aug 05 '15 at 08:51
  • 2
    Considering the potential runtime cost of exception propagation and the necessary stack unwinding, if it can be determined at the point of the offending throw that it will propagate through a function declared `noexcept`, then the program is permitted to immediately terminate, without unwinding any of the stack. For a table-based approach to exception handling, this is in the realm of possibility, to my understanding. Comparing encountering `noexcept` to not, there's the potential for more efficient code to be generated in the `noexcept` case. – Jared Mulconry Aug 05 '15 at 09:09
  • Whether that leads to a performance win or not is going to depend on optimisations of your chosen compiler and the program in question. Certainly when compared to the VC++ behaviour for `throw()`, `noexcept` likely won't measure up in terms of code-gen, but then encountering `noexcept` won't immediately corrupt your program. – Jared Mulconry Aug 05 '15 at 09:13
  • 1
    Okay, thanks for confirming I'm not crazy for thinking noexcept is slightly imperfect from the zero-overhead perspective. Nit-picky as it is, I think I'm going to use a macro-ized token to swap back and forth, at the very least just to get large-scale perf measurements of both ways side-by-side. It's going to take a while to add it to all this code. – VoidStar Aug 05 '15 at 09:26
  • 1
    No worries. If you're able to find similiar functionality on other platforms, then I can see that being useful for certain situations. In terms of the intended behaviour of `throw()`, `noexcept` ought to be better. If my provided answer is acceptable, please mark it accepted for the benefit of others seeking an answer to this question. :) – Jared Mulconry Aug 05 '15 at 09:31
0

By adding noexcept or noexcept(true) specifier to function, you ask compiler to add run-time check and call std::terminate. So you have a small performance hit. You should gain something from it or I can see no sence otherwise. Standard library has traits:

is_nothrow_constructible,
is_nothrow_default_constructible,
is_nothrow_move_constructible,
is_nothrow_copy_constructible,
is_nothrow_assignable,
is_nothrow_move_assignable,
is_nothrow_copy_assignable,
is_nothrow_destructible.

Containers in standard library is known to use these traits on contained types to perform optimization (move instead of copy). Maybe some other optimizations, I don't know about. This make sense for me to add noexcept specifier to appropriate constructor or assignment operator (of course if they really don't throw), that these traits will return true, and get performance boost, when using your class with standard containers.

I don't think that adding noexcept to ordinary function like getter or setter is a good idea: you get performance hit and gain nothing. If your code doesn't throw and doesn't use standard library - my advice: do not use noexcept at all.

Elohim Meth
  • 1,777
  • 9
  • 13
  • _By adding noexcept or noexcept(true) specifier to function, you ask compiler to add run-time check and call std::terminate. So you have a small performance hit._ **No, you do not.** `noexpect` was carefully crafted to introduce **no** overhead. There is **no** run-time check, the call to `std::terminate()` is introduced at the point where an uncaught exception would be thrown. On the contrary `noexcept` gives the compiler (and even more so user code) several optimization opportunities – Fabio Fracassi Aug 06 '15 at 09:21
  • Compiler **can't do magic**. Noexcept has no overhead only if function doesn't call anything or call only noexcept specified functions. In any other case compiler **has to insert run-time check** to determine that exception will not leave the noexcept-ed scope. What optimization opportunities noexcept gives to user or compiler generated code compared to code without any exception specifier? – Elohim Meth Aug 06 '15 at 10:32
  • As I and @Jared 's answer state, what the compiler is allowed to do when it encounters `noexpect` (in contrast to `throw()` or no annotation) is to assume that no stack unwinding takes place. So instead of generating code to throw an exception, unwind the stack, check whether there is a `throw()` on a function and call `std::unexpected()` it is allowed to skip all that and just replace the `throw jadajada` with a call to `std::terminate()` – Fabio Fracassi Aug 06 '15 at 13:00
  • User generated code can do the same thing the library does, i.e. the stuff you describe in your answer – Fabio Fracassi Aug 06 '15 at 13:03
  • In contrast to throw() **yes** in contrast to no annotation **no**. And I can't see any sense to mark function as noexcept and then throw exception in it or call other function that can throw. _Replace the throw jadajada with a call to std::terminate()_ is this optimization?? My understanding of this word is something different. – Elohim Meth Aug 06 '15 at 13:23
  • In VC++ (the compiler I'm using), `throw()` is used for the same optimization opportunities. As far as I can tell, it's exactly like noexcept except with no call to std::terminate (instead resulting in undefined behavior if you somehow threw). Other compilers don't have it, but this might be addressed in the future so I like the macro approach. – VoidStar Aug 06 '15 at 18:54
  • @FabioFracassi: "There is no run-time check, the call to `std::terminate()` is introduced at the point where an uncaught exception would be thrown. " That only sounds possible if everything was all inlined. What if the nothrow is on a function that contains a real call to another function? It can't make that optimization then. It'd have to catch the exception, and that doesn't seem like it can be done without overhead. – VoidStar Aug 06 '15 at 18:56
  • No, the exception handling of modern compilers is more sophisticated, and can do it on separately compiled code. Throwing exceptions is done via a jump table, and the table entries are set by the compiler at the call site (can be done statically). It is to big a topic to explain in a comment (and I am not an expert in it anyway) – Fabio Fracassi Aug 07 '15 at 09:31
  • @VoidStar: throw() will be removed from the standard one day and replaced just with "nothrow" – Lothar Apr 11 '17 at 01:18