Friday 22 March 2013

noexcept

If you've been developing C++ over the last several years you'll probably be aware of exception specifications, and probably not for good reasons. The feature was variably implemented across popular compilers, ranging from "not at all implemented", through to "we'll just do what we like", which led to an unfortunate situation whereby an ANSI-specified feature could not be relied upon as portable code. So far, so disappointing.

The other major problem with exception specifications is that they don't actually help a great deal and their behaviour could be a little... surprising. Their (official) effect was a mixture of compile-time and run-time behaviours, which conspired to not really help all that much while affecting performance more than one might expect.

Consider this sample, which compiles without warning (well, apart from unref'd variables):


 class A {};  
 class B {};  
 class ExceptionTest  
 {  
 public:  
      void throwsB() throw(A)  
      {  
           // whoops, wrong exception spec  
           throw B();  
      }  
 };  
 int main()  
 {  
      ExceptionTest e;  
      try  
      {  
           // expecting a B  
           e.throwsB();  
      }  
      catch(B &b)  
      {  
      }  
      return 0;  
 }  

So... we get no compile-time protection against throwing incorrect exceptions. What we do get is run-time checking, so when an invalid exception is thrown, unexpected() gets called, which by default results in terminate() being called. This behaviour can be customised, but that's not important here.

There is some limited compile-time checking. For example, a function overriding a virtual function can't declare an exception specification that differs from the function it is overriding. Wow. Anyway, exception specifications are dead, so what now? What we really want is some kind of composable, logical compile-time checking that alerts the developer to bugs that would otherwise manifest at run-time. We want something analogous to const correctness.

The C++11 offering is noexcept, and it's similar and it's different. It's similar in that what appears to be a guarantee or a promise is nothing of the sort. In fact, code that violates the noexcept specifier will compile happily and then just make a call to std::unexpected() (and probably to std::terminate()) when the exception is thrown. Hey, at least no exceptions escaped! The reason for this is discussed at length and in excellent detail in Andrzej's C++ blog here

So, is this a rejection of static checking of exceptions? No. It sounds like the standards committee have the same aspiration as the rest of us: to get the compiler to help us by raising an error when an exception could be emitted from some function that has promised not to.

Why does noexcept exist? Currently, it's another compiler hint. If the compiler can rely upon no exception escaping from a function (one way or another), certain optimisations become possible. In the future, maybe compiling identical code with a compiler implementing the next major standard will check your exception guarantees. noexcept has other minor advantages, for which I will again direct you to Andrzej's blog rather than reproducing his good work here.