Note that this question has to do with throwing an exception from the constructor of an exception class, not from any old constructor. I was not able to find a duplicate question on stackoverflow.
This article recommends against throwing such an exception, but I am suspicious of the technical reason given (and the author seems to backtrack on the reason in the comments).
I will give an example and then discuss my interpretation of what's happening, which implies that there basically shouldn't be a problem with doing this, at least from a technical point of view. My main question is whether my interpretation is correct, or if I am missing something conceptually.
Example: Suppose that I want to divide all possible exceptions into two types, User_Error
and Coder_Error
. The former indicates, obviously, that the user did something that they weren't supposed to, and the latter indicates that some serious internal check failed and that someone should file a bug report. Here is a (obviously oversimplified) sketch:
#include <stdexcept>
#include <string>
...
class Coder_Error : public std::runtime_error
{
public:
Coder_Error( const std::string& msg ) :
std::runtime_error( msg + " Please freak out and file a bug report!" )
{}
};
class User_Error : public std::runtime_error
{
protected:
static void check_state() const
{
... // May rely on static members of this class or other classes.
if ( validation_failed ) {
throw Coder_Error( "A useful description of the problem." );
}
}
public:
User_Error( const std::string& msg ) : std::runtime_error( msg )
{
check_state();
}
};
Now suppose that I do throw User_Error( "Some useful message." );
in a case where User_Error::check_state()
will throw. What will happen?
Interpretation: My expectation would be that the Coder_Error
object will get thrown before the throw
in throw User_Error( "Some useful message." )
line is ever encountered, and therefore we do not have to worry about two exceptions being thrown simultaneously, or anything like that. To be more explicit, I expect the relevant steps to occur in something like the following order.
User_Error::User_Error
will get called.
User_Error::check_state
will get called.
Coder_Error::Coder_Error
will get called.
The Coder_Error
object created in step 3 will get thrown.
Stack unwinding will commence and ordinary execution will be stopped, so the execution will never get to a point where it could throw
the User_Error
created in step 1. (I am assuming that no errors are getting caught.)
Is this correct?
As far as I can tell, you're correct that evaluating throw User_Error(...)
has a well-defined result and does not call std::terminate
, provided that the Coder_Error
object is caught by an enclosing handler. GCC and Clang both agree.
Your reasoning is correct for C++14 and below. In C++17, due to mandatory copy elision, the constructor of User_Error
is called during the process of throwing the exception, i.e, once the compiler has already started evaluating the throw
part and has allocated some storage somewhere for the exception object. However, when the construction exits via second exception, the compiler cleans up that storage and proceeds to look for a handler for the second exception. In either case, the result is as you say.
Note that std::terminate
will be called if the copy constructor called during handling of the exception exits via an exception (i.e., as the exception object is being copied into a handler that catches by value) (see example). This is distinct from the situation you have described.