[c++] Throw keyword in function's signature

What is the technical reason why it is considered bad practice to use the C++ throw keyword in a function signature?

bool some_func() throw(myExc)
{
  ...
  if (problem_occurred) 
  {
    throw myExc("problem occurred");
  }
  ...
}

This question is related to c++ exception

The answer is


To add a bit more value to all the other answer's to this question, one should invest a few minutes in the question: What is the output of the following code?

#include <iostream>
void throw_exception() throw(const char *)
{
    throw 10;
}
void my_unexpected(){
    std::cout << "well - this was unexpected" << std::endl;
}
int main(int argc, char **argv){
    std::set_unexpected(my_unexpected);
    try{
        throw_exception();
    }catch(int x){
        std::cout << "catch int: " << x << std::endl;
    }catch(...){
        std::cout << "catch ..." << std::endl;
    }
}

Answer: As noted here, the program calls std::terminate() and thus none of the exception handlers will get called.

Details: First my_unexpected() function is called, but since it doesn't re-throw a matching exception type for the throw_exception() function prototype, in the end, std::terminate() is called. So the full output looks like this:

user@user:~/tmp$ g++ -o except.test except.test.cpp
user@user:~/tmp$ ./except.test
well - this was unexpected
terminate called after throwing an instance of 'int'
Aborted (core dumped)


When throw specifications were added to the language it was with the best intentions, but practice has borne out a more practical approach.

With C++, my general rule of thumb is to only use throw specifications to indicate that a method can't throw. This is a strong guarantee. Otherwise, assume it could throw anything.


The only practical effect of the throw specifier is that if something different from myExc is thrown by your function, std::unexpected will be called (instead of the normal unhandled exception mechanism).

To document the kind of exceptions that a function can throw, I typically do this:

bool
some_func() /* throw (myExc) */ {
}

Well, while googling about this throw specification, I had a look at this article :- (http://blogs.msdn.com/b/larryosterman/archive/2006/03/22/558390.aspx)

I am reproducing a part of it here also, so that it can be used in future irrespective of the fact that the above link works or not.

   class MyClass
   {
    size_t CalculateFoo()
    {
        :
        :
    };
    size_t MethodThatCannotThrow() throw()
    {
        return 100;
    };
    void ExampleMethod()
    {
        size_t foo, bar;
        try
        {
            foo = CalculateFoo();
            bar = foo * 100;
            MethodThatCannotThrow();
            printf("bar is %d", bar);
        }
        catch (...)
        {
        }
    }
};

When the compiler sees this, with the "throw()" attribute, the compiler can completely optimize the "bar" variable away, because it knows that there is no way for an exception to be thrown from MethodThatCannotThrow(). Without the throw() attribute, the compiler has to create the "bar" variable, because if MethodThatCannotThrow throws an exception, the exception handler may/will depend on the value of the bar variable.

In addition, source code analysis tools like prefast can (and will) use the throw() annotation to improve their error detection capabilities - for example, if you have a try/catch and all the functions you call are marked as throw(), you don't need the try/catch (yes, this has a problem if you later call a function that could throw).


Jalf already linked to it, but the GOTW puts it quite nicely why exception specifications are not as useful as one might hope:

int Gunc() throw();    // will throw nothing (?)
int Hunc() throw(A,B); // can only throw A or B (?)

Are the comments correct? Not quite. Gunc() may indeed throw something, and Hunc() may well throw something other than A or B! The compiler just guarantees to beat them senseless if they do… oh, and to beat your program senseless too, most of the time.

That's just what it comes down to, you probably just will end up with a call to terminate() and your program dying a quick but painful death.

The GOTWs conclusion is:

So here’s what seems to be the best advice we as a community have learned as of today:

  • Moral #1: Never write an exception specification.
  • Moral #2: Except possibly an empty one, but if I were you I’d avoid even that.

A no throw specification on an inlined function that only returns a member variable and could not possibly throw exceptions may be used by some compilers to do pessimizations (a made-up word for the opposite of optimizations) that can have a detrimental effect on performance. This is described in the Boost literature: Exception-specification

With some compilers a no-throw specification on non-inline functions may be beneficial if the correct optimizations are made and the use of that function impacts performance in a way that it justifies it.

To me it sounds like whether to use it or not is a call made by a very critical eye as part of a performance optimization effort, perhaps using profiling tools.

A quote from the above link for those in a hurry (contains an example of bad unintended effects of specifying throw on an inline function from a naive compiler):

Exception-specification rationale

Exception specifications [ISO 15.4] are sometimes coded to indicate what exceptions may be thrown, or because the programmer hopes they will improve performance. But consider the following member from a smart pointer:

T& operator*() const throw() { return *ptr; }

This function calls no other functions; it only manipulates fundamental data types like pointers Therefore, no runtime behavior of the exception-specification can ever be invoked. The function is completely exposed to the compiler; indeed it is declared inline Therefore, a smart compiler can easily deduce that the functions are incapable of throwing exceptions, and make the same optimizations it would have made based on the empty exception-specification. A "dumb" compiler, however, may make all kinds of pessimizations.

For example, some compilers turn off inlining if there is an exception-specification. Some compilers add try/catch blocks. Such pessimizations can be a performance disaster which makes the code unusable in practical applications.

Although initially appealing, an exception-specification tends to have consequences that require very careful thought to understand. The biggest problem with exception-specifications is that programmers use them as though they have the effect the programmer would like, instead of the effect they actually have.

A non-inline function is the one place a "throws nothing" exception-specification may have some benefit with some compilers.