#include "Loud.h" Loud a('a'); void foo() { Loud b('b'); Loud c('c'); } int main() { Loud d('d'); foo(); Loud e('e'); return 0; }
Loud::Loud() [c='a'] Loud::Loud() [c='d'] Loud::Loud() [c='b'] Loud::Loud() [c='c'] Loud::~Loud() [c='c'] Loud::~Loud() [c='b'] Loud::Loud() [c='e'] Loud::~Loud() [c='e'] Loud::~Loud() [c='d'] Loud::~Loud() [c='a']
throw
without catch
#include "Loud.h" Loud a('a'); void foo() { Loud b('b'); throw 42; Loud c('c'); } int main() { Loud d('d'); foo(); Loud e('e'); return 0; }
Loud::Loud() [c='a'] Loud::Loud() [c='d'] Loud::Loud() [c='b'] terminate called after throwing an instance of 'int' SIGABRT: Aborted
You can throw anything—doesn’t have to be a special type or object.
try
#1#include "Loud.h" Loud a('a'); void foo() { Loud b('b'); throw "oops!"; Loud c('c'); } int main() { Loud d('d'); try { foo(); } catch (const char *error) { cout << "Caught: " << error << "\n"; } Loud e('e'); return 0; }
Loud::Loud() [c='a'] Loud::Loud() [c='d'] Loud::Loud() [c='b'] Loud::~Loud() [c='b'] Caught: oops! Loud::Loud() [c='e'] Loud::~Loud() [c='e'] Loud::~Loud() [c='d'] Loud::~Loud() [c='a']
try
#2#include "Loud.h" Loud a('a'); void foo() { Loud b('b'); throw "oops!"; Loud c('c'); } void bar() { Loud d('d'); foo(); } int main() { Loud e('e'); try { bar(); } catch (const char *error) { cout << "Caught: “" << error << "”\n"; } Loud f('f'); return 0; }
Loud::Loud() [c='a'] Loud::Loud() [c='e'] Loud::Loud() [c='d'] Loud::Loud() [c='b'] Loud::~Loud() [c='b'] Loud::~Loud() [c='d'] Caught: “oops!” Loud::Loud() [c='f'] Loud::~Loud() [c='f'] Loud::~Loud() [c='e'] Loud::~Loud() [c='a']
catch
#1try { throw "oops!"; } catch (int i) { cout << "int " << i << "\n"; } catch (const char *error) { cout << "C string: " << error << "\n"; } catch (...) { cout << "something\n"; }
C string: oops!
catch
#2try { throw 42; } catch (short s) { cout << "Got a short: " << s << "\n"; } catch (long l) { cout << "Got a long: " << l << "\n"; }
terminate called after throwing an instance of 'int' SIGABRT: Aborted
The type must match. No conversions!
catch
#3// logic_error is-a exception // runtime_error is-a exception // overflow_error is-a runtime_error try { overflow_error oops("OVERFLOW!"); throw oops; } catch (const logic_error &e) { cout << "logic_error: " << e.what() << '\n'; } catch (const runtime_error &e) { cout << "runtime_error: " << e.what() << '\n'; } catch (const exception &e) { cout << "exception: " << e.what() << '\n'; }
runtime_error: OVERFLOW!
catch
#4// logic_error is-a exception // runtime_error is-a exception // overflow_error is-a runtime_error try { overflow_error oops("OVERFLOW!"); throw oops; } catch (const logic_error &e) { cout << "logic_error: " << e.what() << '\n'; } catch (const exception &e) { cout << "exception: " << e.what() << '\n'; }
exception: OVERFLOW!
No conversions, but is-a is good enough.
throw
void foo() { throw string("Division by zero"); } void bar() { try { foo(); } catch (string msg) { if (msg == "Out of memory") // I’ve got this! /* get more memory */; else throw; // Throw up hands in despair. } } int main() { try { bar(); } catch (string problem) { cout << "Problem in bar: " << problem << '\n'; } return 0; }
Problem in bar: Division by zero