There are some articles concluding \"never throw an exception from a destructor\", and \"std::uncaught_exception() is not useful\", for example:
Herb Sutter is talking about the situation when an object of class T is destroyed while there is an uncaught exception in an object of class U. std::uncaught_exception() would return true in the T destructor. The destructor would be unable to find out whether it's called during stack unwinding. If it is, it must not throw, otherwise it's business as usual.
The class U would have a problem using class T in the destructor. U would find itself dealing with a useless T object that would refuse to do anything risky in its destructor (that could include writing a log file or committing a transaction to a database).
Herb Sutter suggests never throwing in a destructor, which is a good idea. However, the C++17 offers another option. It introduced std::uncaught_exceptions(), which can be used to find out whether the destructor can throw. Following example shows the problem if complied in C++14 mode. If compiled in C++17 mode, it would work correctly.
#include
#include
#include
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;
}