[ACCEPTED]-Should I use an exception specifier in C++?-specifier

Accepted answer
Score: 102

No.

Here are several examples why:

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

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

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

  2. Exception-specifications 19 tend to prohibit extensibility.

    virtual void open() throw( FileNotFound );
    

    might evolve 18 into

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

    You could really write that as

    throw( ... )
    

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

  3. Legacy code

    When 14 you write code which relies on another library, you 13 don't really know what it might do when 12 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 11 lib_f() throws. This is (in most cases) not what 10 you really want. std::terminate() should never be called. It 9 is always better to let the application 8 crash with an unhandled exception, from 7 which you can retrieve a stack-trace, than 6 to silently/violently die.

  4. Write code that 5 returns common errors and throws on exceptional 4 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 3 just throws your own exceptions, you can 2 use exception specifications to state your 1 intent.

Score: 42

Avoid exception specifications in C++. The 3 reasons you give in your question are a 2 pretty good start for why.

See Herb Sutter's 1 "A Pragmatic Look at Exception Specifications".

Score: 14

I think the standardly except convention 29 (for C++)
Exception specifiers were an experiment 28 in the C++ standard that mostly failed.
The 27 exception being that the no throw specifier 26 is useful but you should also add the appropriate 25 try catch block internally to make sure 24 the code matches the specifier. Herb Sutter 23 has a page on the subject. Gotch 82

In a addition 22 I think it is worth describing Exception 21 Guarantees.

These are basically documentation 20 on how the state of an object is affected 19 by exceptions escaping a method on that 18 object. Unfortunately they are not enforced 17 or otherwise mentioned by the compiler.
Boost and Exceptions

Exception Guarantees

No Guarantee:

There 16 is no guarantee about the state of the object 15 after an exception escapes a method
In these 14 situations the object should no longer be 13 used.

Basic Guarantee:

In nearly all situations this should 12 be the minimum guarantee a method provides.
This 11 guarantees the object's state is well defined 10 and can still be consistently used.

Strong Guarantee: (aka Transactional Guarantee)

This 9 guarantees that the method will complete 8 successfully
Or an Exception will be thrown 7 and the objects state will not change.

No Throw Guarantee:

The 6 method guarantees that no exceptions are 5 allowed to propagate out of the method.
All 4 destructors should make this guarantee.
| N.B. If 3 an exception escapes a destructor while 2 an exception is already propagating
| the 1 application will terminate

Score: 8

gcc will emit warnings when you violate 5 exception specifications. What I do is 4 to use macros to use the exception specifications 3 only in a "lint" mode compile expressly 2 for checking to make sure the exceptions 1 agree with my documentation.

Score: 7

The only useful exception specifier is "throw()", as 1 in "doesn't throw".

Score: 4

Exception specifications are not wonderfully 27 useful tools in C++. However, there /is/ a 26 good use for them, if combined with std::unexpected.

What 25 I do in some projects is code with exception 24 specifications, and then call set_unexpected() with 23 a function that will throw a special exception 22 of my own design. This exception, upon construction, gets 21 a backtrace (in a platform-specific manner) and 20 is derived from std::bad_exception (to allow 19 it to be propagated if desired). If it causes 18 a terminate() call, as it usually does, the 17 backtrace is printed by what() (as well 16 as the original exception that caused it; not 15 to hard to find that) and so I get information 14 of where my contract was violated, such 13 as what unexpected library exception was 12 thrown.

If I do this, I never allow propagation 11 of library exceptions (except std ones) and 10 derive all my exceptions from std::exception. If 9 a library decides to throw, I will catch 8 and convert into my own hierarchy, allowing 7 for me to always control the code. Templated 6 functions that call dependent functions 5 should avoid exception specifications for 4 obvious reasons; but it's rare to have a 3 templated function interface with library 2 code anyway (and few libraries really use 1 templates in a useful manner).

Score: 3

If you're writing code that will be used 7 by people that would rather look at the 6 function declaration than any comments around 5 it, then a specification will tell them 4 which exceptions they might want to catch.

Otherwise 3 I don't find it particularly useful to use 2 anything but throw() to indicate that it doesn't 1 throw any exceptions.

Score: 3

No. If you use them and an exception is 6 thrown that you did not specify, either 5 by your code or code called by your code, then 4 the default behavior is to promptly terminate 3 your program.

Also, I believe their use has 2 been deprecated in current drafts of the 1 C++0x standard.

Score: 3

A "throw()" specification allows 6 the compiler to perform some optimisations 5 when doing code flow analysis if it know 4 that function will never throw an exception 3 (or at least promises to never throw an 2 exception). Larry Osterman talks about 1 this briefly here:

http://blogs.msdn.com/larryosterman/archive/2006/03/22/558390.aspx

Score: 2

Generally I would not use exception specifiers. However, in 13 cases where if any other exception were 12 to come from the function in question that 11 the program would definitively be unable 10 to correct, then it can be useful. In all cases, make 9 sure to document clearly what exceptions 8 could be expected from that function.

Yes, the 7 expected behavior of a non-specified exception 6 being thrown from a function with exception 5 specifiers is to call terminate().

I will 4 also note that Scott Meyers addresses this 3 subject in More Effective C++. His Effective 2 C++ and More Effective C++ are highly recommended 1 books.

Score: 2

Yes, if you're into internal documentation. Or 8 maybe writing a libary that others will 7 use, so that they can tell what happens 6 without consulting the documentation. Throwing 5 or not throwing can be considered part of 4 the API, almost like the return value.

I 3 agree, they are not really useful for enforcing 2 correctness Java style in the compiler, but 1 it's better than nothing or haphazard comments.

Score: 2

They can be useful for unit testing so that 9 when writing tests you know what to expect 8 the function to throw when it fails, but 7 there is no enforcement surrounding them 6 in the compiler. I think that they are 5 extra code that is not necessary in C++. Which 4 ever you choose all that you should be sure 3 of is that you follow the same coding standard 2 across the project and the team members 1 so that your code remains readable.

Score: 0

From the article:

http://www.boost.org/community/exception_safety.html

“It is well known to be 25 impossible to write an exception-safe 24 generic container.” This claim is often 23 heard with reference to an article by 22 Tom Cargill [4] in which he explores the problem 21 of exception-safety for a generic stack 20 template. In his article, Cargill raises 19 many useful questions, but unfortunately 18 fails to present a solution to his problem.1 17 He concludes by suggesting that a solution 16 may not be possible. Unfortunately, his 15 article was read by many as “proof” of 14 that speculation. Since it was published 13 there have been many examples of exception-safe generic 12 components, among them the C++ standard 11 library containers.

And indeed I can think 10 of ways to make template classes exception 9 safe. Unless you don't have control over 8 all the sub-classes then you may have a 7 problem anyway. To do this one could create 6 typedefs in your classes that define the 5 exceptions thrown by various template classes. This 4 think the problem is as always tacking it 3 on afterwards as opposed to designing it 2 in from the start, and I think it's this 1 overhead that's the real hurdle.

More Related questions