Should I use an exception specifier in C++?

1800 INFORMATION picture 1800 INFORMATION · Sep 18, 2008 · Viewed 26.4k times · Source

In C++, you can specify that a function may or may not throw an exception by using an exception specifier. For example:

void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type

I'm doubtful about actually using them because of the following:

  1. The compiler doesn't really enforce exception specifiers in any rigorous way, so the benefits are not great. Ideally, you would like to get a compile error.
  2. If a function violates an exception specifier, I think the standard behaviour is to terminate the program.
  3. In VS.Net, it treats throw(X) as throw(...), so adherence to the standard is not strong.

Do you think exception specifiers should be used?
Please answer with "yes" or "no" and provide some reasons to justify your answer.

Answer

Christopher picture Christopher · Sep 18, 2008

No.

Here are several examples why:

  1. Template code is impossible to write with exception specifications,

    template<class T>
    void f( T k )
    {
         T x( k );
         x.x();
    }
    

    The copies might throw, the parameter passing might throw, and x() might throw some unknown exception.

  2. Exception-specifications tend to prohibit extensibility.

    virtual void open() throw( FileNotFound );
    

    might evolve into

    virtual void open() throw( FileNotFound, SocketNotReady, InterprocessObjectNotImplemented, HardwareUnresponsive );
    

    You could really write that as

    throw( ... )
    

    The first is not extensible, the second is overambitious and the third is really what you mean, when you write virtual functions.

  3. Legacy code

    When you write code which relies on another library, you don't really know what it might do when something goes horribly wrong.

    int lib_f();
    
    void g() throw( k_too_small_exception )
    { 
       int k = lib_f();
       if( k < 0 ) throw k_too_small_exception();
    }
    

    g will terminate, when lib_f() throws. This is (in most cases) not what you really want. std::terminate() should never be called. It is always better to let the application crash with an unhandled exception, from which you can retrieve a stack-trace, than to silently/violently die.

  4. Write code that returns common errors and throws on exceptional occasions.

    Error e = open( "bla.txt" );
    if( e == FileNotFound )
        MessageUser( "File bla.txt not found" );
    if( e == AccessDenied )
        MessageUser( "Failed to open bla.txt, because we don't have read rights ..." );
    if( e != Success )
        MessageUser( "Failed due to some other error, error code = " + itoa( e ) );
    
    try
    {
       std::vector<TObj> k( 1000 );
       // ...
    }
    catch( const bad_alloc& b )
    { 
       MessageUser( "out of memory, exiting process" );
       throw;
    }
    

Nevertheless, when your library just throws your own exceptions, you can use exception specifications to state your intent.