In this post I would like to share my observation on where using noexcept
really adds value. It is less often than what one might expect, and it does not have that much to do with throwing or not throwing exceptions. The conclusion surprises me a bit, and I hesitate to present it because it is counter to the advice I hear from people I consider authorities on the subject.
Semantics of noexcept
What does it mean to the program that a function is declared as noexcept
? Forget what the intent of the programmer is, or could be. Just answer a ‘technical’ question: what does it change in the program from the perspective of run-time behaviour, observable results and the type system?
Two most important things:
- It turns an exception throw into a call to
std::terminate()
. - One can make a compile-time query if the function has been declared as
noexcept
.
This can be illustrated with the following mean “Hello World” program:
// DON'T DO IT AT HOME! void printMessage() { cout << "Hello World!" << endl; exit(0); } void execute() noexcept { if (noexcept(execute())) throw "Ha!"; } int main() { set_terminate(&printMessage); execute(); }
This is the opposite of any good programming practice, but it illustrates my point well: the intent of putting a feature into the language is one thing and the formal semantics of the feature is another.
There is one other effect of noexcept
, although less interesting for this post. Calling std::terminate()
in the situation above does not require performing stack unwinding, or the stack can be only partially unwound.
Why do you need to know?
Is this an important information for you if a given function may throw or not? If so, why? Some possible answers include the following:
- Because if it throws and I do not catch it,
std::terminate
will be called and I do not want this to happen. - Because I need this function to provide no-throw exception safety guarantee.
- Because this may allow certain compiler optimizations.
Did I miss anything?
If your motivation is (1), noexcept
buys you nothing. While you know that no exception will be propagated out, std::terminate()
is called for you even sooner!
If your motivation is (2), noexcept
will also not help you much. Suppose you detect that the function is not declared as noexcept
, what do you do? Don’t use it? It may still not throw exceptions. A function can throw nothing and still be declared noexcept(false)
. This is the case for the std::swap
specialization for STL containers: following the recommendation from N3248 it is guaranteed not to throw, but is declared noexcept(false)
. For this reason, the example I gave in my other post with function nofail_swap
is wrong. It doesn’t take into account that swap
on STL containers is no-fail. You cannot check the no-fail or no-throw guarantee with a compile-time expression, because in some cases it is just announced informally in the documentation.
Also, if a function is declared noexcept
it can’t throw, but it can call std::terminate
. Do you consider this behaviour suitable for a component that is supposed to be “exception safe”?
If your motivation is (3), then there is a chance that you will gain some performance, but not as much as you think (if any). Compiler can perform certain no-throw optimizations even without your help (especially for inline functions). And annotating anything with noexcept
comes with certain costs: the risk of calling std::terminate
and making function declarations more obscure. C++ allows you to annotate functions wit many information, but when you try to use all of it, function declarations can get really long. Consider these:
constexpr inline int const& getX() const noexcept;
or:
virtual inline int const& getY() const noexcept override [[carries_dependency]];
So unless you are determined you want to have performance squeezed of these noexcept
declarations and you have measured that they actually speed the program up rather than slow it down, I would consider it a premature optimization.
So, what is it for?
Given this negative attitude to noexcept
, can it be considered useful at all? Yes. The noexcept
feature was introduced very late into C++11 to address one particular issue with move semantics. It has been described here by Douglas Gregor and David Abrahams. In short, for certain functions, like vector<T>::push_back
using move constructors/assignments of T
instead of copy constructors/assignments can dramatically increase performance. However, if this move constructor/assignment can potentially throw, push_back
would loose the strong exception safety guarantee. In order to take an advantage of the move operations (where possible) and at the same time keep the strong guarantee, there needs to be a way to determine if a given move operation is potentially throwing or not, and use it or alternatively fall back to good old copying. This is exactly what function std::move_if_noexcept
does, but it needs T
’s operations to be marked as noexcept
where appropriate.
But when is it appropriate, given that a move operation declared as noexcept
may call std::terminate
? (Note that this is the case for std::thread
.) The answer is: you (the author of class T
) decide. If you want the extra performance from vector<T>::push_back
at the risk of loosing the strong guarantee, just add it. You are not risking much if you are ‘sure’ your move operations do not throw. The other part of the guarantee (that std::terminate
is called upon violating noexcept
) is not even necessary here. Only that you are able to declare your choice and that function overload resolution is able to read your choice. In fact, initially the violation of noexcept
was proposed to be an undefined behavior.
So, in other words, the only convincing (for me) usage of noexcept
is to declare to function overload resolution mechanism your resolution of the trade-off between run-time performance and exception safety guarantees. Performance obtained this way can be orders of magnitude greater than noexcept
-based code generation optimizations. Now, I am talking only about annotating move constructors and move assignments this way. This technique could be applied to any function, but so far, I haven’t seen it used for anything else but move operations.
Note that in the description above no throwing of exceptions is mentioned.
It is no-fail, not no-throw
Now, consider the following somewhat unusual definition of a move assignment.
int Tool::operator=(Tool&& rhs) { if (ResourceHandle tmp = getSentinelResource()) { dispose(this->resourceHandle); this->resourceHandle = rhs.resourceHandle; rhs.resourceHandle = tmp; return EXIT_SUCCESS; } else { return EXIT_FAILURE; } }
Nothing in this code throws exceptions. We use a 3rd party library which does not throw exceptions. We do not throw exceptions ourselves: instead we signal failure using the return value.
Now, imagine we are holding our class Tool
in an std::vector
. Do we want to speed up the operations by using moves instead of copies? Since move assignment can fail, the same argument from N2855 still holds, the strong exception safety would be compromised. We do not want that, so we need to signal to the overload resolution mechanism that for our class Tool
we want the copies to be used rather than moves. Therefore our move assignment must not be declared as noexcept
even though we guarantee that we do not throw exceptions! This is because the information that noexcept
really is intended to convey is that the function never fails; not that it never throws! We can see above that a function can fail but still not throw, but it still qualifies for noexcept(false)
. Perhaps the keyword should have been called nofail
. The never-fail guarantee cannot be checked by the compiler (much like any other failure-safety guarantee), therefore the only thing we can do is to declare it.
This is part of a more general observation, that what we are interested in is really failure safety in program components rather than exception safety. No matter if you use exceptions, error return values, errno
or whatever else, the reasoning about basic (no leak, invariant preserved), strong (commit or rollback) and never-fail guarantee should still hold.
More eager termination
There is one other usage of noexcept
(tied to exceptions for a change) that I can think of, but never needed in practice. This is to call std::terminate
more often in hope of finding some failure safety bugs sooner in the application development process.
To illustrate what I mean, consider destructors. If an exception is thrown from a destructor during stack unwinding std::terminate
is called. If this is your design decision that your destructors should throw, calling std::terminate
is an acceptable and desired consequence. On the other hand, if you are trying to apply the best practice widely accepted in C++ community that destructors should not throw, calling std::terminate
in this case is an indication that you inadvertently did throw from a destructor. In that case it is a bug, but one that occurs very seldom. Suppose that you throw from a destructor 1 in 1000 times. Even if you do, it is again 1 in a 1000 times that your exception is called due to stack unwinding. So the probability of calling std::terminate
due to double-exception situation is 1/1000000 (assuming the two events are independent), and is likely not to occur during testing, and only in production. On the other hand, if the destructor is marked as noexcept
, std::terminate
is going to be called whenever an exception is thrown from destructor, during stack unwinding or normal scope exit. So the probability of the throw from destructor being revealed is 1/1000 instead of 1/1000000, and it becomes more likely that we will see it when the program is still in testing stage. And when it happens during testing, the provision that the stack need not be unwound proves very beneficial, because std::terminate
can be called directly at the point of the throw
and we can precisely identify the culprit.
For this reason destructors are implicitly declared noexcept
in C++11. Is this a convincing use case? Answer yourself.
I may be mistaken, but I thought the noexcept operator did not evaluate the expression, and therefore you wouldn’t get a terminte() called for you sooner.
“noexcept buys you nothing. While you know that no exception will be propagated out, std::terminate() is called for you even sooner!”
I am not sure I entirely understand your concern but perhaps the following helps.
There are two different usages of keyword
noexcept
:noexcept
.std::terminate
at run time.So the usage (1) works as you say: evaluates no expression at run-time: no termination. However the declaration (2) changes the behaviour of the program so that it can call
std::terminate
in places where it would otherwise propagate an exception. In a pervert way it does guarantee that the function will not throw: but it offers something potentially worse instead.Isn’t an exception throw converted into `std::terminate` only if it attempts to propagate out from the function that is declared as `noexcept`? I.e. it wouldn’t be changed to `std::terminate` if it is caught before it gets a chance to leave the function?
It is; you are correct.
Interesting article nevertheless! 🙂
Completely agree. Thanks for writing this.
Since Scott Meyers wrote his post about recommending “wider” usage of noexcept I’ve been having nightmares about infinite program execution paths leading to a std terminate call for no win in performance whatsoever.
Would the performance implications be more attractive if throwing out of a noexcept method had undefined behaviour; rather than defined behaviour?
I cannot answer this question with certainty. I have not studied any exception handling implementation in that detail. Based on the opinions of other people (e.g., noted in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3081.pdf), I believe that the provision that stack unwinding is allowed to be broken in case we break the guarantee makes it possible for compilers to generate as effective code (in the no-exception path) as if UB was allowed, at least for some implementations of stack unwinding mechanisms.
No. All modern compilers use what is known as “zero cost” exception handling implementation. This means that not a single instruction of code related to exception handling is executed until an exception is thrown. There are however other costs to such implementations: executable size typically grows by 10-20%, once exception is thrown a lot of code is executed, etc.
“once exception is thrown a lot of code is executed” — and I believe this can be reduced due to
noexcept
Well, yes, calling std::terminate() is one way to avoid executing a lot of code.
“Well, yes, calling std::terminate() is one way to avoid executing a lot of code.” — fair point. I am desperately trying to find an example of performance gain. But it looks like I cannot find any.
> I am desperately trying to find an example of performance gain.
> But it looks like I cannot find any.
Both speed and size compiler optimizations are possible for noexcept functions, but they are exactly the same optimizations which are possible for functions with empty throw() specification.
What you gain with noexcept is the ability to apply these optimizations in more places because you can express a ‘conditional’ or ‘transitive’ noexcept guarantee:
Yes, it’s the only improvement of noexcept over empty throw() specification. But writing such code means taking big risk for tiny gain and I suspect this will not be used much outside of standard library.
“Because this may allow certain compiler optimizations.”
What certain optimizations do you mean?
AFAIK, after compilers convert source code into immediate representation (e.g. GIMPLE for GCC), they can easily remove try-catch boilerplate around pieces that never throw. Do you know what other optimizations are possible that wouldn’t be possible without `noexcept` keyword?
For one, with noexcept compilers can remove try-catch boilerplate even around pieces that do (illegally) throw.
Also, I guess that in order to perform full program analysis you have to do it at link-time (and then it might be too expensive). noexcept allows optimizations during single translation unit processing.
But I am not deep into compiler architecture.
tiny typo in:
…operations (where possible) and at the same keep the strong guarantee, there needs to be a…
s/at the same keep/at the same time keep/
thanks for the blog & cheers,
Martin
Thanks. Fixed.
noexcept kind of reminds me of the C restrict keyword. You can use it to optimize but if you get it wrong (templates, function pointers, virtual functions, any kind of user supplied dynamic dispatch that may throw) god help you.
It seems to me that adding noexcept everywhere could be a great way to introduce bugs into your program for dubious or non-existent optimization benefits. A classical premature optimization.
Thank you for writing this article. I believe your approach is superior to Scott Meyers and others who have been suggesting using noexcept more often. It should probably be restricted to its original intention, that is only if you need to have 2 code paths, one for the function throwing and another for it never throwing (move operations being the main example). I would hope that questions about how to use these new features get resolved before people start writing books and giving advice which later turns out to be not so good.
The holy grail of compile time/run time exception specification and validation in the source code seems like a red herring. We tried once with throw() and now again with noexcept. Perhaps we should give up on this and just focus on how to write exception safe code using RAII. You cannot guarantee any exception specification unless your function has no form of dynamic (compile or runtime) dispatch.
IMO using noexcept is like using const, most notably, its good practice to make ‘extensive’ use of it, but correctly applying it to a legacy code base is a pain, a whole lot of work, and (like in the early days of const correctness) puts severe limitations on the libraries you can use. Just like we don’t say we should not use const because libraries may ‘mutable’ themselves out of the const contract, it does equally not seem like a good idea to promote such a thing for what I would like to call noexcept correctness. The important thing about const correctnes in the light of ‘mutable’ is the same as the important thing about noexcept correctness in the light of throwing anyway: “stick to the bleeding contract!”
There is one difference though, between the two. In case of
const
, compiler support comes in two parts: (1) it makes use of yourconst
annotations, but also (2) it immediately detects your inadvertent violations of const-ness. True, you can mutate when you are determined to do so, but you cannot do it by mistake. In case ofnoexcept
you get compiler support only for the first part. This difference is significant enough — IMO — to say thatnoexcept
-correctness cannot be recommended with the equal enthusiasm asconst
-correctness.It would have been nice to just prevent exceptions from being caught instead of throwing std::terminate(), so we can have a core-dump or the debuger-stop with a stack that goes as far as it can get, and with more state to be analyzed. That way we could just put noexcept everywhere and start opening every function one by one once we have modified them to throw the correct exceptions. This pass is not normally done at first-write, at least I don’t. First I write my functions as if every uncatched exceptions will behave like an assert, and then begin modifying them to throw appropriate ones. The problem with this approach is that I don’t really know if they’re not gonna be caught, I leave it to chance. That version of noexcept would have helped me a lot, knowing that at first every thrown exception will behave like an assert (which in practice the majority of them should), and then as a second “QA” pass begin the preparation for throwing and catching the appropriate exceptions.
Pingback: What’s New in ReSharper C++ 2016.2 | ReSharper C++ Blog
Fantastic write-up and the only clear and thorough explanation I have found thus far.
Thank you.
You forget about bare-metal targets.
For example, GNU ARM Embedded toolchain for Cortex-M.
First project: just two files, main.cpp and a.cpp
main.cpp:
extern int a();
int main() {return a();}
a.cpp:
extern int a() {return 0;}
After correct linking, program size is 5024 bytes, compiler add calls to __aeabi_unwind_cpp_pr0(), __gnu_unwind_execute() and link a very fat library code to service non-existing exceptions, there are sections .ARM.extab and .ARM.exidx in resulting elf file.
If I change two source files with noexcept for function a(), then program size is only 460 bytes (more than 10 times less) and no unwinding service routines are added by linker.
So, for embedded project there is reason to use noexcept to remove appropriated functions from section .ARM.extab and .ARM.exidx and possibly to fully remove a fat and useless library code to service non-existing exceptions.
Thanks for sharing this! Apparently, the same observation can be made for other cross-translation-unit optimizations (or lack thereof).
Or let me ask you this. If you have a single-file program:
There is no noexcept annotation, but everything is in one TU. What size is your binary then?
460 bytes.
I did some experiments with that, exception tables are used for different object files.
A little typo triggering to infinities 🙂
“So the probability of the throw from destructor being revealed is 1/1000 instead of 1/000000 …”
Indeed 🙂 thanks.
You’re welcome. 🙂
Great article. My take is that noexcept is fine. Look, there are really two use-cases here. (A) You wrote a custom function/method that you know does not throw. How do you know this? Because you didn’t type “throw”. Not rocket science. This covers 80 – 90% of cases. (B) You wrote some function that calls some 3rd party lib func and or calls another func….and in either case you are either too lazy or simply unable to figure out if the func you are calling inside the func can throw. In such a case you can wrap everything in the func in a try catch and not re-throw. Problem solved. You should mark every method as noexcept that you can. C++ does not have exception specifications(deprecated — cause like many things in C++…it never worked right)… so the programmer must be defensive and assume that anything that is not marked with noexcept can throw. Of course, great article anyway.
And I agree, that the compilers should be smart enough to catch you explicitly throwing. Perhaps not functions you are calling inside the function though. So… the lesson is that when you say noexcept… don’t lie…it is on you to ensure it does not throw. You can easily guarantee this as described above.
Good programmer don’t use exceptions. There is a good reason why exceptions are verboten at Google. They have 4000 c++ devs and it is strictly forbidden. These are the top programmers int he world. If you think exception are a good idea…just think about this. Why do the best progs forbid its usage? One of the many probs with exceptions is that there can be a throw just about anyplace. In a collaborative group… you just have no idea who did what. This is almost like goto’s being place ad-hoc. There is no requirement for the caller at any level to check anything. It is completely up in the air who checks (cathes what) what. It can just bubble up and crash. So oyu need some baseline where you can guarantee that at that point you have checked/cought everything and you don’t trow/re-throw. That is what noexcept is. Programmers are lazzy. That’s why bad programmer love exceptions. They can put off dealing with issues at the callers level one level up (the way good programmers do) and can pass on the task to someone else. Lazzy lazzy. You need a baseline guarantee sometime. So…we need a way to ensure some sanity. Exception specs are a good idea… but apparently beyond the abilities of the c++ folks to get right… so the next best thing is noexcept. With that we can guarantee that a function does not throw.
Now, that you have mentioned Google’s Style Guide, let’s see what they have to say about using exceptions: https://google.github.io/styleguide/cppguide.html#Exceptions.
Quoting some relevant parts:
So it is not that they are saying, “we are not using exceptions because we are the top programmers”.
Also, what people describe as “anything can be thrown from anywhere” is not disturbing once you realize the dependency between function calls. If function
f
needs to call functionp
and functionq
in order to succeed, and then, when functionp
needs to call functionsa
,b
andc
in sequence in order to succeed:We can see that
p
depends ona
,b
andc
, and ifa
should fail, there is no point in callingb
orc
anymore, becausep
will fail anyway, and sincep
will fail, there is no point in callingq
either, becausef
will also inevitably fail anyway.This pattern of function call dependency is so common that you would expect the language to support it by default. The only thing you need to take care then is to identify the places where this dependency does not hold and spell them out explicitly:
I guess it boils down to adapting a certain mind-set. And if one refuses to do it, one will indeed conclude that that the language with exceptions makes everything harder.
Cuz u asked what is it for. That’s what it is for. Return state/code is the best way. While God nor compiler forces you to check return codes, it is industry standard that each function checks params and other things and returns its own success state. An then the caller checks that state. It is clear who does what. And while people who don’t know how to code think you have to propogate up return codes, you don’t. You call an errorHandler() func at the callers level. Each func only returns its own success state. The errorHandler() func can log the error or what ever you want and can be as descriptive as you want. Very clean and felxible. Easy to code review. THE POINT… think of it like this… no one will tell you this… but us in the secret Order of Return Codes had the C++ committee create noexcept to indirectly manipulate people into (A) wirting code that does not throw, and (B) suppress code bubbling up in into their functions. In short, we got Google to do our bidding and now the c++ committee. Muahahaha
Unless you are already familiar with it, I recommend taking a look at Niall Douglas’ Outcome Library. It allows you to indicate failures in function returns (no exceptions), but at the same time preserves function dependency chains, so that you do not have to put if-statements everywhere and you cannot just forget about handling some return code.
you are wrong about one thing, if you don’t want a function to call ‘terminate’, that is not the reason to Not declare it as ‘noexcept’. if you don’t want terminate to be called, you must write your software correctly instead.
because if it throws, you may face resource leak.
using exception safe resources in a function may be a unnecessary implementation or may even cost you some extra instructions.
Thank you for the comment. I must admit I am not able to parse the following sentence:
— It uses three negatives. Maybe if you could restate this statement with fewer negatives?
— I think I agree with this one.
— if who throws? Or do you mean, “if
std::terminate()
is called”? Yes, calling terminate could cause a resource leak, but what resource do you mean?std::terminate()
has been designed exactly for this purpose: to clean up resources that are not recycled automatically by the system upon program exit. So, calling it can actually prevent leaks.We could make another statement, and maybe this is what you meant: a correct program never invokes
std::terminate()
.While I like your kind of reasoning, I think you are somewhat “cheating” here (no offense, you almost got me).
Consider your Tool::operator=(Tool&&) from above: Why don’t you simply throw an exception on failure instead of relying on old C-style return semantics? I mean, throwing an exception is supposed to be the way to signal a failure in C++ (at least in the context of the noexcept specifier), i.e., nofail noexcept.
Arguing that specifying noexcept for your Tool::operator=(Tool&&) is semantically wrong (which it clearly is in your case) when you escape from that function by non-exceptional means on failure, is like manipulating a class via a pointer to its memory region and then complaining that the class’ invariant is broken.
The point is: Use noexcept if and only if you do return all failures from a function via exceptions and your particular function does not throw (i.e., has no failures).
Pingback: unordered_set::find and noexcept - Tutorial Guruji