I don't tend to use exception specifications, but not for the reason that will become apparent as you read this post...

I'm writing I presentation on exception safety, and wanted to write a short bit on exception specifications. So to give an example of behaviour, I wrote the following bit of code with the intention of expanding it in the next slide or so:

Code:
#include <iostream>
#include <stdexcept>

void f() throw()
{
  throw std::runtime_error("blah");
}

int main()
{
  try
  {
    f();
  }
  catch(const std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
}
Since I figure someone might ask for the slides and try to run the examples, I thought I should check my examples compile and run. The interesting thing is, with this example Visual Studio 2008 doesn't do what I'd expect. Before I say anymore I'd like to point out that the 2003 C++ Standard states the following:

Whenever an exception is thrown and the search for a handler (15.3) encounters the outermost block of a function with an exception-specification, the function std::unexpected() is called (15.5.2) if the exception-specification does not allow the exception. [ Example:
Code:
class X { };
class Y { };
class Z: public X { };
class W { };

void f() throw (X , Y)
{
  int n = 0;
  if (n) throw X (); / / OK
  if (n) throw Z (); / / also OK 
  throw W (); / / will call std::unexpected()
}


The function std::unexpected() may throw an exception that will satisfy the exception-specification for which it was invoked, and in this case the search for another handler will continue at the call of the function with this exception specification (see 15.5.2), or it may call std::terminate().
In addition the 2011 C++ Standard states:

Whenever an exception is thrown and the search for a handler (15.3) encounters the outermost block of a function with an exception-specification that does not allow the exception, then,
— if the exception-specification is a dynamic-exception-specification, the function std::unexpected() is called (15.5.2),
— otherwise, the function std::terminate() is called (15.5.1).
[ Example:
Code:
  class X { };
  class Y { };
  class Z: public X { };
  class W { };

  void f() throw (X, Y) {
    int n = 0;
    if (n) throw X(); // OK
    if (n) throw Z(); // also OK
    throw W(); // will call std::unexpected()
  }
—end example ]

[ Note: A function can have multiple declarations with different non-throwing exception-specifications; for this purpose, the one on the function definition is used. —end note ]

10 The function unexpected() may throw an exception that will satisfy the exception-specification for which it was invoked, and in this case the search for another handler will continue at the call of the function with this exception-specification (see 15.5.2), or it may call std::terminate().
With respect to behaviour, I have the following points:

1) If I compile the example code as is, here is what I'd expect. The exception thrown in f() will not allowed to be propagated, instead, the default unexpected_handler will be called which in-turn will call std::terminate().

GCC does as expected, however, Visual Studio 2008 does something very different...

In release mode (running within the IDE) at run-time the debugger throws up an unhandled exception message box, if I say continue, it seemingly gets stuck in an infinite loop of breakpoint triggers and throwing up unhandled exception boxes around the same code section. The default unexpected_handler doesn't appear to ever be called. If run outside of the IDE a the console states:

"This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information."

and a just-in-time debugger window gets thrown up.

In debug mode (both when run inside the IDE and outside the IDE), it is almost as if the throw() specifier doesn't exist, the exception is propagated and caught in the catch statement. The default unexpected_handler does not get called and the program exits uneventfully with code 0.

2) If I modify the example as follows adding in the user defined function unexpected_exception_handler and calling set_unexpected:

Code:
#include <iostream>
#include <stdexcept>

void f() throw()
{
  throw std::runtime_error("blah");
}

void unexpected_exception_handler() 
{  
  std::cout << "unexpected_exception_handler: Unexpected exception caught" << std::endl;
  std::terminate();
}

int main()
{
  std::set_unexpected( &unexpected_exception_handler );

  try
  {
    f();
  }
  catch(const std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
}
I would expect that the user defined unexpected_exception_handler function will be called, which will in-turn call terminate. Again, GCC behaves as expected. But Visual Studio 2008 doesn't, at least not quite.

In release mode, if run outside of the IDE, the VS compilation behaves the same as the previous release compilation (when outside the IDE with the just in time debugger window being thrown up). The user defined unexpected_exception_handler doesn't get called.

If run inside the IDE, then continuing past an unhandled exception box and a host of breakpoint triggers, the compilation does call the user defined unexpected_exception_handler and the calls terminate, exiting gracefully with code 3.

In debug mode (both when run inside the IDE and outside the IDE), the VS compilation behaves the same as the previous debug compilation, propagating the exception that is then caught in the catch statement and then it exits uneventfully (but incorrectly) with code 0.

3) If I move the call to set_unexpected to within the try block as follows:

Code:
#include <iostream>
#include <stdexcept>

void f() throw()
{
  throw std::runtime_error("blah");
}

void unexpected_exception_handler() 
{  
  std::cout << "unexpected_exception_handler: Unexpected exception caught" << std::endl;
  std::terminate();
}

int main()
{
  try
  {
    std::set_unexpected( &unexpected_exception_handler );
    f();
  }
  catch(const std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
}
then GCC still behaves as expected, but Visual Studio does something different again.

In both release and debug modes (both when run inside and outside the IDE), it behaves as if the throw() specifier does not exist, propagating the exception to the catch block and then exiting with code 0. In all cases for this third version of the example, the user defined unexpected_exception_handler is not called.

If any of you have a later version of Visual Studio (I'm using 2008 Professional 9.0.21022.8), can you see if you get the same behaviour? Either way, unless you can see that I have done something really stupid, I'm thinking of raising a compiler bug.

So much for writing a bit of demo code to demonstrate exception specifications!