throw() in function signature in C++

2013-11-23
#c++ #exceptions

There is a base class exception in the standard library (header <exception>). It has a default constructor, copy constructor, copy operator, destructor, and a virtual what() function. The latter returns a string with additional information about the exception.

1#include <exception>
2class MyException: public std::exception
3{
4    virtual const char* what() const throw()
5    {
6        return "My Exception happened";
7    }
8}

The most confusing part in the above code is throw(). It assures that no exception will be thrown from the what() function. For example, if you want to allow the exceptions int and float to be raised in this function, you must write throw(int, float) (you cannot do it in the above example; this function definition is fixed in the base class). OK, this example is mostly unchangeable, so let’s write our own MyException class without deriving from any standard library class.

 1#include <iostream>
 2#include <string>
 3
 4class MyException
 5{
 6public:
 7    std::string what()
 8    {
 9        return "MyException happened";
10    }
11};
12
13int main(int argc, char **argv)
14{
15    MyException a;
16    try {
17        throw a;
18    } catch (MyException &e) {
19        std::cout << e.what() << std::endl;
20    } catch (int a) {
21        std::cout << "int thrown " << a << std::endl;
22    }
23
24    return 0;
25}

OK, if you copy the source code, compile it, and run it, you’ll see:

1$ g++ main.cpp -o throw
2$ ./throw
3MyException happened

This behavior is predictable. The exception is thrown and caught by catch (MyException &e). No special modifiers are present.

Let’s change the example a little (throwing an exception from what()):

 1#include <iostream>
 2#include <string>
 3
 4class MyException
 5{
 6public:
 7    std::string what()
 8    {
 9        throw 10;
10        return "MyException happened";
11    }
12};
13
14int main(int argc, char **argv)
15{
16    try {
17        MyException a;
18        throw a;
19    } catch (MyException &e) {
20        std::cout << e.what() << std::endl;
21    }
22    return 0;
23}

Throwing an exception from what() causes an unhandled exception:

1$ ./throw
2terminate called after throwing an instance of 'int'
3Aborted (core dumped)

Using throw() in a function declaration is considered a bad idea. But in this particular situation it is allowed: what() returns an additional description, so it must not send any other exception, as there is no guarantee that this exception will be handled. Restrict exceptions from what():

 1#include <iostream>
 2#include <string>
 3
 4class MyException
 5{
 6public:
 7    std::string what() throw()
 8    {
 9        throw 10;
10        return "MyException happened";
11    }
12};
13
14int main(int argc, char **argv)
15{
16    try {
17        MyException a;
18        a.what();
19    } catch (...) {
20        std::cout << "exception handled" << std::endl;
21    }
22    return 0;
23}

Finally we get what we came for: this class is pretty much like std::exception, isn’t it? throw() ensures that no exceptions can be sent from the what() function. So, will the compiler fail? No! The compiler reports no errors. But an error occurs at runtime:

1$ ./throw
2terminate called after throwing an instance of 'int'
3Aborted (core dumped)

There is little information about why the code failed. No exception (even one raised in functions called from what()) will pass through what() throw(). The error will appear only at runtime.

So, throw() is used to ensure that no additional exceptions will be raised from the what() function and escape catch(). But in the general case such behavior is difficult to predict and is bad practice. Try not to use throw() in a function signature without strong necessity. Try not to use throw with particular allowed exceptions (like throw(A, B)) in any situation. The standard std::exception is very good to derive your exceptions from in a huge number of situations.