从C ++中的异常构造函数中抛出异常

时间:2018-10-05 18:24:12

标签: c++ exception constructor throw

请注意,此问题与从异常类的构造函数 而不是从任何旧的构造函数引发异常有关。我在stackoverflow上找不到重复的问题。

This article建议不要抛出此类异常,但是我对给出的技术原因感到怀疑(作者似乎在评论中回溯了原因)。

我将举一个例子,然后讨论对正在发生的事情的解释,这意味着至少从技术角度来看,这样做基本上不应该有问题。我的主要问题是我的解释是否正确,或者我在概念上是否缺少某些东西。

示例:假设我想将所有可能的异常分为两种类型,User_ErrorCoder_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." )之前被抛出,因此我们不会必须担心同时抛出两个异常或类似的异常。更明确地说,我希望相关步骤按以下顺序进行。

  1. User_Error::User_Error将被呼叫。

  2. User_Error::check_state将被呼叫。

  3. Coder_Error::Coder_Error将被呼叫。

  4. 在步骤3中创建的Coder_Error对象将被抛出。

  5. 堆栈展开将开始,并且常规执行将停止,因此执行将永远无法达到步骤1中创建的throw User_Error的地步。(我假设没有错误被捕获。)

这正确吗?

1 个答案:

答案 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)。这与您描述的情况不同。