|
|
A general performance design goal of the C++ language is the maxim:
If you don't use a language feature, you don't pay for it.
But with exception handling this is somewhat difficult to achieve. Even the most innocuous-looking code:
void f() { A a; g(); }will have a performance burden for exception handling, because if A is a class with a destructor and g() is a function that might throw an exception, then the C++ runtime system has to know that object a must be destroyed when the stack frame for f() is unwound.
This compiler attempts to minimize this distributed performance overhead, by tracking try blocks, catch handlers, and object lifetimes with program-counter-based tables of instruction ranges built at compile- and link-time, rather than with execution-time data structures and operations. These tables are created in special new sections, of new section types, within the object format, and in dynamic linking contexts are not relocated until and unless needed.
This has the following benefits:
In other words, performance tradeoffs have been selected to minimize
the effect of exception handling when no exceptions are thrown, at the
sacrifice of performance for the case where exceptions are thrown.
So a new maxim becomes:
Only use throw exceptions in exceptional situations
Note the phrasing "no direct execution-time overhead ..." above. There is some indirect cost to optimization (CC -O) due to exception handling, because certain kinds of optimizations must be suppressed lest they interfere with the range tables that the C++ runtime uses to process exceptions.
There is one area in which application programmers can further minimize the effects of exception handling support. This is by using exception specifications. When functions have empty exception specifications, the compiler knows that no exception can be thrown back through a call to such a function. Taking the above example, if function g() is declared as
void g() throw();then the compiler may be able to generate less exception handling support information for function f(). Furthermore, if the constructors and destructors for class A are also declared with empty exception specifications
class A { A() throw (); ~A() throw (); };then the compiler can tell that an exception cannot possibly be raised within function f(), and no exception handling support information need be generated at all. Use of exception specifications may also help minimize optimization degradation due to exception handling.
Note however that exception specifications should be used only when appropriate. If the natural way a function would report an error condition is through an exception, then it should be written that way, unless there are extreme performance considerations involved. In particular, throwing an exception is almost always the best way for a constructor to indicate an error.