Exceptions are an important part of modern programming. In C++, they may add a slight amount to the memory footprint of your program, but in terms of runtime execution, they are often faster than non exception alternatives (see side-note). When you add the benefits of code clarity, I think exceptions are the way to go.
This tutorial will illustrate the writing of custom exception classes, show how to throw these new classes, and how to catch them.
Compile the source code with the following commands:
g++ -c -o except.o except.cpp g++ -o except except.o
Running the resulting executable should produce output of the following variety:
$ ./except
0: Caught a basic FruitException:
FruitException
1: Caught an AppleException:
FruitException: Apples are rotten
2: Caught a basic FruitException:
FruitException: Bananas are getting brown
3: Got away clean!
$
class FruitException: public std::exception { public: FruitException(); virtual ~FruitException() throw(); virtual const char *what() const throw(); protected: std::string sWhat; };
We derive our class from the "std::exception" class, which provides a "what" function that returns a null-terminated "const char *" explaining the exception.
We are also going to allocate some space to store this "what" information in the form of a std::string "sWhat". By making this class variable "protected" we allow our child classes access to it, without exposing it to the public.
class AppleException: public FruitException { public: AppleException(std::string sDetail); virtual ~AppleException() throw(); };
The AppleException class sub-classes FruitException. This time, we are going to take an additional string on the constructor to give more information about the specific circumstances that produced the exception. Note: we do not re-implement the "what" function, the function we wrote in FruitException will suffice.
The BananaException class is nearly identical to the AppleException class.
FruitException::FruitException(): sWhat("FruitException") { } FruitException::~FruitException() throw() { } const char *FruitException::what() const throw() { return sWhat.c_str(); }
In the constructor for FruitException, we set our "sWhat" string to "FruitException". Our destructor does nothing special. In the "what" function, we simply return a "char *" version of the data in "sWhat".
AppleException::AppleException(std::string sDetail)
{
sWhat += ": Apples are ";
sWhat += sDetail;
}
AppleException::~AppleException() throw()
{
}
In the AppleException constructor, our "sWhat" has already been set to the string "FruitException" by our parent class. We are going to append some more data to that string, including the detail information that was passed into this constructor ("sDetail").
The "what()" function in FruitException will simply return all the data in sWhat, including the data we have appended to it.
throw FruitException(); throw AppleException("rotten"); throw BananaException("getting brown");
When it comes time to throw your exceptions, you can just create them in line with the throw keyword as shown. The apple and banana exceptions take a single string intended to describe the circumstances of the exception.
try { //exceptions get thrown here... } catch( AppleException &e ) { std::cout << "Caught an AppleException: " << std::endl; std::cout << "\t" << e.what() << std::endl; } catch( FruitException &e ) { std::cout << "Caught a basic FruitException: " << std::endl; std::cout << "\t" << e.what() << std::endl; }
When a section of your code is likely to generate an exception that you wish to catch, wrap it in a "try" block and create "catch" blocks for the exceptions you wish to trap. Note in the above code that we did not create a specific catch block for "BananaException"s. They will be caught in the "FruitException" block as Bananas are a child class of FruitException. Indeed when a BananaException is thrown in our test program, we saw the result was:
2: Caught a basic FruitException:
FruitException: Bananas are getting brown
With this template you should be able to create exception classes to be thrown and caught in your code. Before you go write a bunch of classes, however, take a moment to consider the structure of your class hierarchy. What structure makes the most sense, and is going to be the most useful to the people who are going to be catching your exceptions?