[cfe-dev] The really scary part of noexcept

Johannes Schaub (litb) schaub.johannes at googlemail.com
Sun Mar 20 08:17:21 PDT 2011


Sebastian Redl wrote:

> Hi,
> 
> There's one small piece of the noexcept specification left to implement.
> It's not only scary, it's also fiendishly difficult to find, being the
> only part of noexcept that isn't within [except]. [class.dtor]p3 says:
> 
> "A declaration of a destructor that does not have an
> exception-specification is implicitly considered to have the same
> exception-specification as an implicit declaration."
> 
> This means that destructors suddenly grow exception specifications, and
> they may be really, really wrong. Consider this little class, which could
> be used as an RAII guard.
> 
> class TransactionGuard {
>   DatabaseConnection& m_conn;
> public:
>   TransactionGuard(DatabaseConnection& conn) : m_conn(conn) {}
>   ~TransactionGuard() {
>     if (std::unhandled_exception()) { // if we're being destructed due to
>     an exception being thrown
>       try { conn.rollback(); } catch(...) {} // rollback and swallow any
>       errors, or we terminate
>     } else {
>       conn.commit(); // otherwise commit, and let exceptions escape
>     }
>   }
> };
> 
> The above destructor would suddenly grow an exception-specification.
> Specifically, because it has no object data members, the
> exception-specification would be empty: it would be noexcept(true). If the
> conn.commit() call throws, the program would immediately terminate instead
> of letting the exception escape.
> 
[...]
> So my question is, how should we implement this in Clang? Simply put it
> under C++0x? Have it enabled in C++0x by default, but add a switch to turn
> it off? Add an explicit switch to turn it on?
> 

In my opinion, the situation for a program that does not use 
std::uncaught_exception() to check whether there currently is an unhandled 
exception is not worsened by this, because if the exception is thrown, it 
already has the risk of having terminate called. 

So I wonder whether the following makes sense:

- Implement it according to the spec, and when you process the body:
 - When the destructor does not have an explicit exception specification but 
a nonthrowing implicit exception specification, and 
 - when the body contains a call to std::uncaught_exception

If the two conditions are satisfied, issue a warning that 
terminate/unexpected will be called regardless of the return value of 
std::uncaught_exception() when an exception escapes the body. 

I don't quite understand whether the exception specification will be 
"throw()" or "noexcept(true)". It seems to make a difference wrt whether 
unexpected() or teminate() is called. Subsection 15.4 hasn't enlighted me: 
It just says that the function disallows any exception. 





More information about the cfe-dev mailing list