TICV2.1.Exception Handling

  • traditional error handling:
    • return value or set global error variable.
    • signal() & raise()
    • setjmp() & longjmp()
      C++ standard states: branching into a scope with goto, or branching out of a scope with longjmp() where an object on the stack has a destructor, constitutes undefined behavior.
  • you can use any type when you throw(including built-in types).
  • Stack unwinding : any local objects(exclude objects allocated on heap) created by the time the exception occurs are destroyed automatically.
  • polymorphism works for exceptions and you should catch by reference to avoid "object-slicing"
  • an object or reference to a derived-class object will match a handler for the base class.
    no automatic type conversions are used to convert one exception type to another in the process of matching
  • it make more sense to catch the derived types first and put the base type at the end to catch anything less specific
  • catch(...) means catching any type of exception
  • you can rethrow the exception by using throw with no argument inside a handler
  • terminate() is automatically called
    • if no handler at any level catches the exception
    • if a destructor for a local objects throws an exception while stack is unwinding
    • if a global or static object's constructor or destructor throws an exception
  • DO NOT allow a destructor to throw an exception
  • use set_terminate(func) to customize your terminate()
    func() must take no arguments and return void, and can NOT throw any exception
  • C++ exception handing guarantees that as you leave a scope, all objects in that scope whose constructors have been completed will have their destructor called.(it should be your design principle, the compiler doesn't do it ???)
  • constructors that aren't completed don't have the associated destructor called
  • Resource management
    • if you allocate resources in constructors and the constructor throws an exception, then the destructror doesn't get a chance to deallocate the resource.
    • to avoid resource leaks, you can:
      • catch exceptions inside the constructor and release the resource
      • make everything an object -- Resource Acquisition Is Initialization (RAII)
    • auto_ptr: an handy tool
  • function level try blocks
  • standard exceptions

exception specification

  • “void f()” means that any type of exception can be thrown
  • “void f() throw()” means that no exceptions whatsoever will be thrown
  • unexpected() is called when you throw something other than what appears in the exception specification
  • you can use your own unexpected() by using set_unexpected(), your custom function should have no arguments and return void
  • a typical unexpected handler logs the error and terminates the program by calling exit(), however, it can throw another exception(or rethrow the same exception) or call abort()
  • if unexpected handler rethrow the same exception:
    • if std::bad_exception was in the function’s exception specification, the exception throw from the unexpected handler is replaced with a std::bad_exception object, and the search resumes from the function as before.
    • if the original function’s specification did not include std::bad_exception, terminate() is called
  • if a member function in a base class says it will only throw an exception of type A, an override of that function in a derived class must not add any other exception types to the specification list, it can specify fewer exceptions or none or anything that “is-a” A in place of A
  • if you don’t know what exceptions might occur, don’t use exceptionn specifications
    Exception specifications are mainly for non-template classes

 

Exception Safety: you should know why pop() in STL stack container doesn’t return a value.

Programming with Exceptions:

some guidelines:

When to avoid exception:

  • Best advice: throw exceptions only when a function fails to meet its specification
  • Not for asynchronous events
  • Not for benign error conditions
    if you have enough information to handle an error, solve the problem in the current context rather than throwing an exception to a larger context
  • Not for flow of control
  • You’re not forced to use exceptions

Typical uses of exceptions

  • fix the problem and retry the function that caused the exception
  • patch things up and continue without retrying the function
  • do whatever you can in the current context and rethrow the same exception to a higher context
  • do whatever you can in the current context and throw a different exception to a higher context
  • terminate the program
  • wrap functions that use ordinary error schemes so they produce exceptions instead
  • simplify your error handling scheme
  • make your library and program safer

  • anytime you use exception specifications, consider creating your own unexpected() function
  • start with standard exceptions
  • nested your own exceptions
  • use exception hierarchies
  • catch by reference, not by value
  • throw exception in constructor
  • DO NOT cause exceptions in destructor
  • avoid naked pointers

Comments