5

According to Optimizing C++,

Use the empty exception specification (that is, append throw() to the declaration) for the functions you are sure will never throw exceptions.

What if I know that 90% of my methods won't throw an exception? It seems unconventional and verbose to append throw() to all of those methods. If not, what are the advantages? Or am I misunderstanding something here?

Agrim Pathak
  • 3,047
  • 4
  • 27
  • 43
  • Won't applying `nothrow` detect actually possible violations at compiletime? (just to get a 100% sure) – πάντα ῥεῖ Nov 06 '14 at 20:46
  • do you have a good reason and an up-to-the-task codebase to use exceptions or you are just using them because you believe they are good and working 100% of the time by default ? – user2485710 Nov 06 '14 at 20:47
  • Don't worry about it except for the functions you know to be a bottle-neck in your code. – Mark Ransom Nov 06 '14 at 20:47
  • A little dated now, but: http://www.gotw.ca/publications/mill22.htm – Fred Larson Nov 06 '14 at 20:52
  • What are the advantages? Did you read the article that you linked? The whole point is discussing the advantages of those optimizations. Are you hand compiling your code? If not, have you written a compiler that reads your mind? If not, how exactly do you expect the compiler to pick up the information that 90% of your functions won't throw exceptions? Yes, it is verbose, but that's the price you pay to extract out extra optimization. If you don't care about the optimization, don't bother. – iheanyi Nov 07 '14 at 00:14
  • BTW, not throwing exceptions means in addition to your functions not throwing exceptions themselves, they won't call anything which throws an exception or which might call code that may throw an exception (and so forth). – iheanyi Nov 07 '14 at 00:19

2 Answers2

9

C++11 has introduced noexcept, throw is somewhat deprecated (and according to this less efficient)

noexcept is an improved version of throw(), which is deprecated in C++11. Unlike throw(), noexcept will not call std::unexpected and may or may not unwind the stack, which potentially allows the compiler to implement noexcept without the runtime overhead of throw().

When an empty throw specification is violated, your program is terminated; this means you should only declare your functions as non throwing, only when they have a no throw exception guarantee.

Finally you need a move constructor to be non throwing (specified with noexcept) to be able to use the r-value ref version of std::vector<T>::push_back (see a better explanation here)

Community
  • 1
  • 1
Lorah Attkins
  • 5,331
  • 3
  • 29
  • 63
5

The standard throw() doesn't enhance optimizability.

If a method is marked as throw() then the compiler is forced to check if an exception is thrown from the method and unwind the stack - just like if the function is not marked as throw(). The only real difference is that for a function marked throw() the global unexpected_handler will be called (which generally calls terminate()) when the exception leaves the function, unwinding the stack to that level, instead of the behavior for functions without an exception specification which will handle the exception normally.

For pre-C++11 code, Sutter & Alexandrescu in "C++ Coding Standards" suggested:

Avoid exception specifications.

Take exception to these specifications: Don’t write exception specifications on your functions unless you’re forced to (because other code you can’t change has already introduced them; see Exceptions).

...

A common but nevertheless incorrect belief is that exception specifications statically guarantee that functions will throw only listed exceptions (possibly none), and enable compiler optimizations based on that knowledge

In fact, exception specifications actually do something slightly but fundamentally different: They cause the compiler to inject additional run-time overhead in the form of implicit try/catch blocks around the function body to enforce via run-time checking that the function does in fact emit only listed exceptions (possibly none), unless the compiler can statically prove that the exception specification can never be violated in which case it is free to optimize the checking away. And exception specifications can both enable and prevent further compiler optimizations (besides the inherent overhead already described); for example, some compilers refuse to inline functions that have exception specifications.

Note that in some versions of Microsoft's compilers (I'm not sure if this behavior has changed in more recent versions, but I don't think so), throw() is treated in a non-standard way. throw() is equivalent to __declspec(nothrow) which does allow the compiler to assume that the function will not have an exception thrown and undefined behavior will result if one is.

C++11 deprecates the C++98 style exception specification and introduced the noexcept keyword. Bjarne Stroustup's C++11 FAQ says this about it:

If a function declared noexcept throws (so that the exception tries to escape, the noexcept function) the program is terminated (by a call to terminate()). The call of terminate() cannot rely on objects being in well-defined states (i.e. there is no guarantees that destructors have been invoked, no guaranteed stack unwinding, and no possibility for resuming the program as if no problem had been encountered). This is deliberate and makes noexcept a simple, crude, and very efficient mechanism (much more efficient than the old dynamic throw() mechanism).

In C++11 if an exception is thrown from a function marked as noexcept the compiler is not obligated to unwind the stack at all. This affords some optimization possibilities. Scott Meyers discusses the new noexcept in his forthcoming book "Effective Modern C++".

Michael Burr
  • 333,147
  • 50
  • 533
  • 760