**Error Handling** In C++ code I see two popular and somewhat incompatible ways of handling errors: exceptions and return codes. Discussions with colleagues on which one to use almost always boils down to this incompatibility. Everyone argues for the approach they've been using thus far, because it works with the code they've written so far. I believe, on its own, that is a weak argument, especially since bridgen the two appraoches is far from impossible. Occasionally, I've also seen colleagues argue for some parts of one approach, without using the others. I argue that the two approaches are a complete package. You either use all of it, or nothing. # Exceptions + Early Return + RAII ```c++ struct thing_t { thing_t() { // May throw. } bool is_admin() { // May return false. return true; } void do() { // May throw. throw std::runtime_error("Error"); } }; void do_thing() { auto thing = std::make_unique<thing_t>(); if (!thing->is_admin()) { return; } thing->do(); } ``` Pros: * Usually shorter code. * Function is allowed to exit at any point. Destructors are called implicitly. * Consistent with `std`. Cons: * Clean-up code is not visible. * Code, that should always run before leaving a function, has to be placed in destructors. * Non-RAII types, from C libraries for example, need to be wrapped in new RAII types. # Linear Code ```c++ struct thing_t { bool do() { // May fail. return false; } bool is_admin() { // May return false. return true; } }; thing_t *make_thing() { // May fail and return nullptr. return new thing_t(); } bool do_thing() { thing_t *thing = make_thing(); bool error = false; if (!thing) { error = true; } if (!error && !thing->is_admin()) { error = true; } if (!error) { error = thing->do(); } delete thing; return error; } ``` Pros: * Function always executes from beginning to end. Clean-up code is put at the end of the function, where it is visible. Cons: * Usually longer code. * Easy to accidentally forget clean-up code. Note that I repeatedly check `error`. An alternative version I often see is to nest the branches. I also see colleagues try to use early returns in code like this, requiring the clean-up code to be repeated before each return. I am not a fan of either. *I am aware that this code behaves slightly different, as when `is_admin` returns `false`, it errors, whereas the other example doesn't. Usually I would see code where `error` is an enumerate type containing some non-error values for this case.* # Mixed Use As mentioned in the intro, care must be taken when mixing the two approaches. Individual functions should only use one approach, and calls to functions using the other approach need to be wrapped. ## Calling Linear Code from RAII Code ```c++ struct thing_t { bool do() { // May fail. return false; } bool is_admin() { // May return false. return true; } }; thing_t *make_thing() { // May fail and return nullptr. return new thing_t(); } void destroy_thing(thing_t *thing) { delete thing; } struct thing_deleter_t { void operator()(thing_t *thing) { destroy_thing(thing); } }; void check(bool error) { if (error) { throw std::runtime_error("Error"); } } void do_thing() { std::unique_ptr<thing_t, thing_deleter_t> thing(make_thing()); check(!thing); if (!thing->is_admin()) { return; } check(thing->do()); } ``` In personal projects I write code like this when interfacing with C APIs. *I want to write an example using `std::out_ptr`.* ## Calling RAII Code from Linear Code ```c++ struct thing_t { thing_t() { // May throw. } bool is_admin() noexcept { // May return false. return true; } bool do() { // May throw. throw std::runtime_error("Error"); } }; bool do_thing() { bool error = false; thing_t *thing = nullptr; try { thing = new thing_t(); } catch (...) { error = true; } if (!thing->is_admin()) { error = true; } if (!error) { try { error = thing->do(); } catch (...) { error = true; } } delete thing; return error; } ```