class: middle #A Practical Approach to Error Handling --- #Error Handling and Exceptions ```cpp file f("file.txt"); ``` -- What happens if the file does not exist? -- - return value ```cpp file f; bool bOk=f.open("file.txt"); if( !bOk ) {...} ``` * not for ctor - out parameter ```cpp bool bOk; file f("text.txt",bOk); if( !bOk ) {...} ``` * both clutter code with checks * user can forget to check --- #Error Handling and Exceptions (2) - status: bad flag on first failure * single control path * good if checking at the very end is good enough * writing a file - ok * reading a file - maybe not * otherwise like out parameter * default for C++ iostreams --- #Error Handling and Exceptions (3) - exception -- * Catch exception objects always by reference * Slicing * Copying of exception may throw -> `std::terminate` ```cpp struct A {...}; struct B : A {...}; try { throw B(); } catch( A a ) { // B gets sliced and copied into a ... throw; // throws original B }; ``` --- #Exceptions - work like multi-level return/goto - add invisible code paths ```cpp auto inc(int i)->int { // throw(char const*) if(3==i) throw "Hello"; return i+1; } auto main()->int { try { int n=3; inc(n); // throw(char const*) n=42; } catch( char const* psz ) { std::cout << psz; } return 0; } ``` --- #Error Handling and Exceptions (4) ```cpp auto inc(int i, char const* & pszException )->int { { if(3==i) { pszException="Hello"; goto exception; } return i+1; } exception: return 0; } ``` --- #Error Handling and Exceptions (4) ```cpp auto main()->int { char const* pszException=nullptr; { int n=3; inc(n,pszException); if( pszException ) goto exception; n=42; return 0; } exception: { std::cout << pszException; return 0; } } ``` -- Stop whining! Of course must write exception-safe code! --- #Exception Safety Guarantees (not really exception-specific) Part of function interface - Never Fails -- - Strong Exception Guarantee: * may fail (throw), but will restore program state to what it was before: transactional * possible and desirable in library functions * very hard in application code * usually too many state changes -- - Basic Exception Guarantee: * may fail (throw), but will restore program to some valid state --- #Basic Exception Safety Guarantee Customer: "Hello, is this Microsoft Word support? I was writing a book. Suddenly, Word deleted everything." Microsoft: "Oh, that's ok. Word only provides a basic exception guarantee." Customer: "Oh, alright then, thank you very much and have a good day!" --- #The Challenge - Error handling is a lot of effort * in testing (many codepaths to test) * if you don't test them, they won't work * in development (must be paranoid) - little customer gain -- - Poll: What do YOU do? * check API calls? * on failure? * on failed asserts? -- - People skip error checking because they don't know what to do! --- #So what do we do? - Check everything * check every API call * one wrapper per error reporting method * Windows: `GetLastError()`, `HRESULT` * Unix: `errno` * `assert` aggressively * asserts stay in Release * `noexcept` if caller does not handle exception * `std::terminate`, but unexpected exceptions will terminate anyway * some exceptions impossible to handle: `std::bad_alloc` * install handler with `std::set_terminate` for checking Goal: Keep program on narrow path of correctness! -- - Handle nothing --- #If checks fail - prio 1: collect as much information as possible * send reports home * halt server thread and notify operator - prio 2: carry on somehow * if check was critical, we are in undefined behavior land: no further reports * never terminate! * asserts can be wrong, too! * if you need safety (nuclear powerplant, etc.), add at higher level * example: our server stops processing certain types of request if too many threads hang --- #Next: Homework - Reproduce the error in the lab - Add handling code only for errors that are reproducible * Otherwise you will write * error handlers that are never used * error handlers that are never tested and so likely do the wrong thing 5% of handlers handle 95% of errors --- #Categories of errors ``` immediate crash likely? yes--> Level 6 ex: imminent Desktop User: nullptr - error dialog access (false alarm no unlikely, | increase chance | of getting | more info) | v and program behavior no---> Level 5 well-defined? Desktop User: ex: assert failed - disable future reports yes (future is ill- | defined) | Our Server: | - infinite loop | (wait for debugger) | v and ``` --- ``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BORDER TO UNDEFINED BEHAVIOR LAND vvv Programmer may have expectations of how program behaves vvv - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - situation has been no---> Level 4 tested? Desktop User: ex: condition found Our Server: that has never been - send report reproduced Debug Build: yes - error dialog | (repro found!) | v and user experience is good no---> Level 3 ex: 3rd party Desktop User: bug we did Our Server: not completely - log work around (explains yes behavior | if we get | complaints) | v and ``` --- ``` situation may be indication yes--> Level 2 of broken program Desktop User environment during remote support session: no - error dialog | (get attention | of support eng) | v and situation occurs no---> Level 1 in every run/code path Desktop User during remote yes support session: | Debug: | - log | (analyze to v learn about path to All good failure) ``` --- #A Very Special Class of Errors ```cpp std::int32_t a=2 000 000 000; std::int32_t b=a+a; ``` What is `b`? -- Uuh, may overflow. - Let's check for it! ```cpp if( b