#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 (...) { // Gotta catch ’em all! 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
#2½try { throw "Son of a gun!"; } catch (string s) { cout << "Got a string: " << s << "\n"; }
terminate called after throwing an instance of 'char const*' SIGABRT: Aborted
Why didn’t that work?
catch
#2¾try { throw "That’s better."s; } catch (string s) { cout << "Got a string: " << s << "\n"; }
Got a string: That’s better.
Hey, that worked!
catch
#2⅞try { throw "Even better."s; } catch (const string &s) { cout << "Got a string: " << s << "\n"; }
Got a string: Even better.
This works, and is more efficient. Of course, efficiency may not be an issue here.
catch
#3// logic_error is-a exception // runtime_error is-a exception // overflow_error is-a runtime_error try { throw overflow_error("Just too big!"); } 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: Just too big!
catch
#4// logic_error is-a exception // runtime_error is-a exception // overflow_error is-a runtime_error try { throw overflow_error("Just too big!"); } catch (const logic_error &e) { cout << "logic_error: " << e.what() << '\n'; } catch (const exception &e) { cout << "exception: " << e.what() << '\n'; }
exception: Just too big!
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