1 / 16

Overview of C++ Exceptions

Overview of C++ Exceptions. Normal program control flow is halted At the point where an exception is thrown The program call stack “unwinds” Stack frame of each function in call chain “pops” Variables in each popped frame are destroyed Goes until an enclosing try/catch scope is reached

Download Presentation

Overview of C++ Exceptions

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Overview of C++ Exceptions • Normal program control flow is halted • At the point where an exception is thrown • The program call stack “unwinds” • Stack frame of each function in call chain “pops” • Variables in each popped frame are destroyed • Goes until an enclosing try/catch scope is reached • Control passes to first matching catch block • Can handle the exception and continue from there • Can free some resources and re-throw exception

  2. C++ Exceptions Example • Consider a program using a Number class • We’ve not covered class member functions in detail yet • Class member functions are much like “plain-old” functions • But are given a hidden extra pointer to the object (“this”) • One of the class member functions is operator /= • Divides value object contains by another passed value • Problem: what if someone passes 0 to this function?

  3. void Number::operator/=(const double denom) { if (denom == 0.0) { // what do we do here? } m_value /= denom; } Need to handle divide by zero case Otherwise bad things happen Program crash Wrong results Could set value to NaN Special “not-a-number” value But, caller might fail to check for it Could return a “special” value Might be a valid return value Could still be ignored Exceptions offer a better alternative Motivation for C++ Exceptions

  4. void foo() throw (int) { throw 2; } catch (int &i) { cout << i << endl; } catch (...) { cout << “another exception” << endl; } Can throw any type Can specify what a function (only) throws in it’s declaration Can catch and use exceptions in code “Default” catch block C++ Exception Syntax

  5. In general, structure is common A chunk of memory representing the state of an active function call Pushed on program call stack at run-time g++ -s gives assembler output can be used to deduce exact structure for a given platform Contains: The previous frame pointer The return address for the call (i.e., just after the point from which it was called) Parameters passed to the function Automatic (stack) variables for the function What’s in a Stack Frame? local (automatic) variables parameters previous frame pointer return address

  6. int main (int argc, char **argv) { Number n(8.1); try { n /= 0.0; cout << n << endl; } catch (int) { return 1; } return 0; } Stack frame for function main Pushed on program call stack With stack variables i and c With parameters argc and argv Note that parameters are initialized at frame creation Variables are not necessarily initialized at frame creation May occur later in called function Illustrating the Call Stack n m_value main argc argv

  7. int main (int argc, char **argv) { Number n(8.1); try { n /= 0.0; cout << n << endl; } catch (int) { return 1; } return 0; } Number constructor called Stack frame created Initializing an Object (Constructor Call) Number:: Number(const double n) n this n m_value main argc argv

  8. Number::Number(const double num) :m_value(n) { } Enter Number constructor m_value is set in n How do we know which m_value to set? Implicit this pointer Constructor Executes num Number::Number(const double num) this n m_value main argc argv

  9. Number::Number(const double num) :m_value(n) { } Return from constructor Stack frame is popped Return to main Constructor Finishes n m_value main argc argv

  10. int main (int argc, char **argv) { Number n(8.1); try { n /= 0.0; cout << n << endl; } catch (int) { return 1; } return 0; } Call operator/= on n New stack frame created Copy 0.0 into n Setthis Calling Operator /= Number:: operator/=(const double denom) denom this n m_value main argc argv

  11. Test denom against 0.0 Test succeeds throw integer 0 Exception Thrown void Number::operator/=(const double denom) { if (denom == 0.0) { throw 0; } m_value /= denom; } denom Number::operator/=(const double denom) this n m_value main argc argv

  12. Skips over rest of function Control returns to caller Continues until try/catch scope Live Exception Unwinds Stack void Number::operator/=(const double denom) { if (denom == 0.0) { throw 0; } m_value /= denom; } n m_value main argc argv

  13. int main (int argc, char **argv) { Number n(8.1); try { n /= 0.0; cout << n << endl; } catch (int) { return 1; } return 0; } We’ve reached an enclosing try/catch scope So stack unwinding stops Control jumps to first matching catch block Skips over intervening coutstatement Catching the Exception n m_value main argc argv

  14. try { // can throw exceptions } catch (Derived &d) { // Do something } catch (Base &d) { // Do something else } catch (...) { // Catch everything else } Control jumps to first matching catch block Order matters if multiple possible matches Especially with inheritance-related exception classes Put more specific catch blocks before more general ones Put catch blocks for more derived exception classes before catch blocks for their respective base classes catch(...) catches any type throw; does not throw a type essentially a call to abort() A Few More Details

  15. // can throw anything void Foo::bar(); // promises not to throw void Foo::bar() throw(); // promises to only throw int void Foo::bar() throw(int); // throws only char or int void Foo::bar() throw(char,int); Make promises to the caller Allow stronger type checking enforced by the compiler By default, a function can throw anything it wants A throw clause in a function’s signature Limits what can be thrown A promise to calling function A throw clause with no types Says nothing will be thrown Can list multiple types Comma separated Exception Specifications

  16. Good Programming Style with C++ Exceptions • Don’t use exceptions for normal program flow • Only use where normal flow isn’t possible • Don’t let exceptions leave main or constructors • Violates “normal” initialization and termination • Always throw some type • So the exception can be caught • Use exception specifications widely • Helps caller know possible exceptions to catch

More Related