void someFunc() noexcept; // more optimization opportunities ... maybe unwind a stack in case of exception (offers compiler writers more optimization opprotunities)... Ex 1. If during mem-allocation one of the elt-move-ctor throws the exception, we just have a basic (not strong ex.guarantee). For strong-guarantee, only non-throwing move acceptable std::vector::push_back uses std::move_if_noexcept -> cast to RVal only if T's move know to not throw. ... or we don't have a copy c-tor (move c-tor can throw) noexcept declaration is an INTERFACE promise (not just a current impl) noexcept stands for notexcept(true) noexcept(false) not guarantee not to throw This is usefull for conditional ex-safety guarantee (at templates) noexcept is also an operator: tepmpate void f(T && param) noexcept(noexcept(*param)); **************** * Alexandrescu * **************** std::promise std::future template class Expected { union { T ham; std::exception_ptr spam; }; bool gotHam; Expected() {} // used internally public: Expected(const T& rhs) : ham(rhs), gotHam(true) { } Expected(T&& rhs) : ham(std::move(rhs)), gotHam(true) { } Expected(const Expected& rhs) : gotHam(rhs.gotHam) { if (gotHam) new(&ham) T(rhs.ham); else new(&spam) std::exception_ptr(rhs.spam); } Expected(Expected&& rhs) : gotHam(rhs.gotHam) { if (gotHam) new(&ham) T(std::move(rhs.ham)); else new(&spam) std::exception_ptr(std::move(rhs.spam)); } ~Expected() { using std::exception_ptr; if (gotHam) ham.~T(); else spam.~exception_ptr(); } void swap(Expected& rhs) { if (gotHam) { if (rhs.gotHam) { using std::swap; swap(ham, rhs.ham); // peek up this-namespace swap if available, otherwise - std::swap } else { auto t = std::move(rhs.spam); new(&rhs.ham) T(std::move(ham)); new(&spam) std::exception_ptr(t); std::swap(gotHam, rhs.gotHam); } } else { if (rhs.gotHam) { rhs.swap(*this); } else { spam.swap(rhs.spam); std::swap(gotHam, rhs.gotHam); } } } // Note: std::exception is thrown by value, but catch by reference (with d-tor and what() polymorphic stuff). template static Expected fromException(const E& exception) { if (typeid(exception) != typeid(E)) { throw std::invalid_argument("slicing detected"); } return fromException(std::make_exception_ptr(exception)); } static Expected fromException(std::exception_ptr p) { Expected result; result.gotHam = false; new(&result.spam) std::exception_ptr(std::move(p)); return result; } static Expected fromException() { return fromException(std::current_exception()); } bool valid() const { return gotHam; } T& get() { if (!gotHam) std::rethrow_exception(spam); return ham; } const T& get() const { if (!gotHam) std::rethrow_exception(spam); return ham; } template bool hasException() const { try { if (!gotHam) std::rethrow_exception(spam); } catch (const E& object) { return true; } catch (...) { } return false; } // auto r = Expected::fromCode([] { // ... // }); template static Expected fromCode(F fun) { try { return Expected(fun()); } catch (...) { return fromException(); } } }; // Ex1 Expected parseInt(const std::string& s) { int result; ... if (nonDigit) { return Expected::fromException(std::invalid_argument("not a number")); } ... if (tooManyDigits) { return Expected::fromException(std::out_of_range("overflow")); } ... return result; } // Caller string s = readline(); auto x = parseInt(s).get(); // throw on error auto y = parseInt(s); // won’t throw if (!y.valid()) { // handle locally if (y.hasException()) { // no digits ... } y.get(); // just "re"throw }