Herb Sutter talks about a situation where an object of class T destroyed, while in an object of class U there is an uncaught exception. std::uncaught_exception() will return true in the T destructor. The destructor will not be able to find out if he called it during the unwinding of the stack. If so, he should not quit, otherwise this is the case as usual.
Class U will have a problem using class T in the destructor. U discovers that it is dealing with a useless object T that refuses to do anything risky in its destructor (this may include writing a log file or committing a transaction to a database).
Grass Sutter suggests never throwing a destructor, which is a good idea. However, C ++ 17 offers another option. It introduces std::uncaught_exceptions() , which can be used to find out if the destructor can throw. The following example shows the problem if it is running in C ++ 14 mode. If it is compiled in C ++ 17 mode, it will work correctly.
#include <exception> #include <iostream> #include <string> class T { public: ~T() noexcept(false) { #if __cplusplus >= 201703L // C++17 - correct check if (std::uncaught_exceptions() == uncaught_exceptions_) #else // Older C++ - incorrect check if (!std::uncaught_exception()) #endif { throw (std::string{__PRETTY_FUNCTION__} + " doing real work"); } else { std::cerr << __PRETTY_FUNCTION__ << " cowardly quitting\n"; } } private: #if __cplusplus >= 201703L const int uncaught_exceptions_ {std::uncaught_exceptions()}; #endif }; class U { public: ~U() { try { T t; } catch (const std::string &e) { std::cerr << __PRETTY_FUNCTION__ << " caught: " << e << '\n'; } } }; int main() { try { U u; throw (std::string{__PRETTY_FUNCTION__} + " threw an exception"); } catch (const std::string &e) { std::cerr << __PRETTY_FUNCTION__ << " caught: " << e << '\n'; } return 0; }
proski
source share