On Sun, Aug 7, 2016 at 5:22 PM, Gavin Lambert
On 8/08/2016 01:06, Lorenzo Caminiti wrote:
void fclose(file& f) noexcept { if (!f.is_open()) preconfition_failure_handler(from_function); ...
Where by default the handler terminates:
precondition_failure_handler = [] (from) { std::terminate(); };
But programmers can redefine it to throw (as you suggested above, but beware of what N4160 points out plus on how to program a throwing entry_invariant_failure_handler that shall not throw when from == from_destructor):
precondition_failure_handler = [] (from) { throw failed_precondition(); };
Or to log and exit:
precondition_failure_handler = [] (from) { some-logging-code; exit(-1); };
Or to take any other action programmers wish to take on precondition failure.
It is an error for a noexcept function to call a non-noexcept function outside of a try-catch block.
I guess you could argue this is a programming error... in any case, the standard just says that std::terminate() will be called as the exception tries to escape the noexcept function.
It therefore follows that if precondition_failure_handler is callable in that manner, it must be noexcept, and therefore cannot throw. Otherwise something is fundamentally broken.
The precondition (or any other contract) failure will always result in a call to std::terminate() by the noexcept function even if the precondition_failure_handler (or any other contract handler) is programmed to throw, that's all.
Whether the caller is a destructor or not is irrelevant; this applies to any noexcept method.
True. I have used destructors just because they are a well known example of functions that should (almost always) be noexcept. The same reasoning applies to any other noexcept function.
Any code that makes special cases for destructors (other than to treat them as noexcept even if not specified) is probably also erroneous.
Yes, in fact you can say the following code is making sure to treat destructors noexcept even when they are not explicit specified noexcept (i.e., making sure destructors (noexcept or not) do not throw on contract failures even when the contract failure handlers are configure to throw exceptions for contracts that fail from functions other than destructors): entry_invariant_failure_handler = [] (from where) { if(where != from_destructor) throw entry_invariant_failure(); std::terminate(); } Thanks, --Lorenzo