CHAPTER 25

image

Exception Handling

Exception handling allows programmers to deal with unexpected situations that may occur in a program.

Throwing Exceptions

When a function encounters a situation that it cannot recover from it can generate an exception to signal the caller that the function has failed. This is done using the throw keyword followed by whatever it is the function wants to signal. When this statement is reached, the function will stop executing and the exception will propagate up to the caller where it can be caught, using a try-catch statement.

nt divide(int x, int y)
{
  if (y == 0) throw 0;
  return x / y;
}

Try-catch statement

The try-catch statement consists of a try block containing code that may cause exceptions and one or more catch clauses to handle them. In the above case an integer is thrown and so a catch block needs to be included that handles this type of exception. The thrown expression will get passed as an argument to this exception handler, where it can be used to determine what has gone wrong with the function. Note that when the exception has been handled, the execution will then continue running after the try-catch blocks and not after the throw statement.

try {
  divide(10,0);
}
catch(int& e) {
  std::cout << "Error code: " << e;
}

An exception handler can catch a thrown expression by either value, reference or pointer. However, catching by value should be avoided since this causes an extra copy to be made. Catching by reference is generally preferable. If the code in the try block can throw more types of exceptions then more catch clauses need to be added to handle them as well. Keep in mind that only the handler that matches the thrown expression will be executed.

catch(char& e) {
  std::cout << "Error char: " << e;
}

To catch all types of exceptions an ellipsis (...) can be used as the parameter of catch. This default handler must be placed as the last catch statement since no handler placed after it will ever be executed.

catch(...) { std::cout << "Error"; }

Re-throwing Exceptions

If an exception handler is not able to recover from an exception it can be re-thrown by using the throw keyword with no argument specified. This will pass the exception up the caller stack until another try-catch block is encountered. Be careful however, because if an exception is never caught the program will terminate with a run-time error.

int main()
{
  try {
    try { throw 0; }
    catch(...) { throw; } // re-throw exception
  }
  catch(...) { throw; }   // run-time error
}

Exception Specification

Functions are by default allowed to throw exceptions of any type. To specify the exception types that a function may throw the throw keyword can be appended to the function declaration. The throw keyword is followed by a comma separated list of the allowed types, if any, enclosed in parentheses.

void error1() {}            // may throw any exceptions
void error2() throw(...) {} // may throw any exceptions
void error3() throw(int) {} // may only throw int
void error4() throw() {}    // may not throw exceptions

This kind of exception specification is very different from the one used in for example Java, and overall there is very little reason to specify exceptions in C++. The compiler will not enforce the specified exceptions in any way and it will not be able to make any optimizations because of them.

Use of throw for exception specification was deprecated in C++11 and replaced by a noexcept specifier. Similar to throw(), this specifier indicates that a function is intended not to throw any exceptions. The main difference is that noexcept enables certain compiler optimizations, because the specifier allows the program to terminate without unwinding the call stack if for any reason an exception still occurs.

void foo() noexcept {} // may not throw exceptions

Exception Class

As previously mentioned, any data type can be thrown in C++. However, the standard library does provide a base class called exception which is specifically designed to declare objects to be thrown. It is defined in the exception header file and is located under the std namespace. As seen below, the class can be constructed with a string that becomes the exception’s description.

#include <exception>
void make_error()
{
  throw std::exception("My Error Description");
}

When catching this exception the object’s function what can be used to retrieve the description.

try { make_error(); }
catch (std::exception e) {
  std::cout << e.what();
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.72.176