请注意,此问题与从异常类的构造函数 而不是从任何旧的构造函数引发异常有关。我在stackoverflow上找不到重复的问题。
This article建议不要抛出此类异常,但是我对给出的技术原因感到怀疑(作者似乎在评论中回溯了原因)。
我将举一个例子,然后讨论对正在发生的事情的解释,这意味着至少从技术角度来看,这样做基本上不应该有问题。我的主要问题是我的解释是否正确,或者我在概念上是否缺少某些东西。
示例:假设我想将所有可能的异常分为两种类型,User_Error
和Coder_Error
。很明显,前者表明用户做了他们不应该做的事情,而后者表明某些严重的内部检查失败了,有人应该提交错误报告。这是一个(显然过于简化的)草图:
#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();
}
};
现在假设在throw User_Error( "Some useful message." );
会抛出的情况下我执行User_Error::check_state()
。会发生什么?
解释:我的期望是,Coder_Error
对象将在遇到throw
行中的throw User_Error( "Some useful message." )
之前被抛出,因此我们不会必须担心同时抛出两个异常或类似的异常。更明确地说,我希望相关步骤按以下顺序进行。
User_Error::User_Error
将被呼叫。
User_Error::check_state
将被呼叫。
Coder_Error::Coder_Error
将被呼叫。
在步骤3中创建的Coder_Error
对象将被抛出。
堆栈展开将开始,并且常规执行将停止,因此执行将永远无法达到步骤1中创建的throw
User_Error
的地步。(我假设没有错误被捕获。)
这正确吗?
答案 0 :(得分:3)
据我所知,如果throw User_Error(...)
对象被一个std::terminate
对象捕获,那么对Coder_Error
的定义是正确的,并且不会调用User_Error
是正确的。封装处理程序。 GCC and Clang both agree。
您的推理对C ++ 14及以下版本是正确的。在C ++ 17中,由于强制复制省略,在编译器已经开始评估{{1时,在抛出异常 ie 的过程中,将调用throw
的构造函数。 }}部分,并为异常对象分配了一些存储空间。但是,当构造通过 退出第二个异常时,编译器将清理该存储,并继续查找第二个异常的处理程序。无论哪种情况,结果都如您所说。
请注意,如果在异常的处理期间调用的复制构造函数通过异常( ie 退出,则会调用std::terminate
>,因为异常对象被复制到按值捕获的处理程序中(see example)。这与您描述的情况不同。