【问题标题】:Is there a way to tell that the program is in process of throwing an exception?有没有办法告诉程序正在抛出异常?
【发布时间】:2017-10-25 04:18:36
【问题描述】:

我的问题的简短版本

在堆栈上分配了一个类型 A 的对象。在它的析构函数 ~A() 中,有没有办法判断析构函数是否被调用是因为抛出了异常并且堆栈正在展开,还是仅仅因为定义它的范围“自然”结束?我尝试检查std::current_exception 是否不为空,不起作用。

加长版

我必须支持一个旧 API:

void MyApi()
{
    try
    {
        MyTimeTracker mtt;
        //do API stuff
    }
    catch(...)
    {
        //handle exception
    }
}

如果API stuff抛出异常,表示API失败,否则表示成功。 MyTimeTracker 检查API stuff 的执行花费了多少时间——它测量构造函数中的开始时间和析构函数中的结束时间,并将其报告给数据库。

现在我希望它也报告 API 调用是否成功。有没有办法在析构函数中说明这一点?

我不允许在第一个 try 块之外分配它,因为整个 API 代码必须在 try 块中。我可以将API stuff 放入第一个内部的单独 try 块中,然后重新抛出,但这看起来很难看。

我尝试在析构函数中检查std::current_exception,但它为空,即使我们正在抛出异常。

【问题讨论】:

    标签: c++ c++11 exception exception-handling


    【解决方案1】:

    没有像您描述的那样检测堆栈展开状态的标准便携式方法。

    但是有一个更简单的解决方案。给MyTimeTracker添加一个布尔成员,如果API成功则设置,然后在析构函数中检查。

    MyTimeTracker::MyTimeTracker()
    {
        ...
        success = false;
    }
    
    MyTimeTracker::~MyTimeTracker()
    {
        ...
        if (!success) {
            ... 
        }
    }
    
    void MyApi()
    {
        try
        {
            MyTimeTracker mtt;
            //do API stuff
            mtt.success = true;
        }
        catch (...)
        {
            //handle exception
        }
    }
    

    更新:

    这样做的主要原因是报告错误代码,它位于异常中。

    然后您必须求助于第二个try/catch 来获取错误代码,将其存储在mtt 对象中以在析构函数中执行,然后重新抛出:

    MyTimeTracker::MyTimeTracker()
    {
        ...
        errCode = 0;
    }
    
    MyTimeTracker::~MyTimeTracker()
    {
        ...
        if (errCode != 0) {
            ... 
        }
    }
    
    void MyApi()
    {
        try
        {
            MyTimeTracker mtt;
            try
            {
                //do API stuff
            }
            catch (const the_api_error &e)
            {
                mtt.errCode = ...; // error code from e... 
                throw;
            }
        }
        catch (...)
        {
            //handle exception
        }
    }
    

    【讨论】:

    • 有时显而易见的简单就是如此优雅。
    • 这在我的情况下不起作用。我不想详细说明,但这样做的主要原因是报告错误代码,它位于异常上。唉。不过还是谢谢。
    • @remy-lebeau 似乎 std::uncaught_exception 正是为此目的而设计的:en.cppreference.com/w/cpp/error/uncaught_exception。但是它不会让您看到异常实际上是什么
    • @Valentin:我以前从未听说过std::uncaught_exception()。但就像你说的,你无法访问实际的异常,所以你必须实际捕获它,以便从中复制数据
    猜你喜欢
    • 2020-07-23
    • 2019-10-24
    • 1970-01-01
    • 1970-01-01
    • 2015-07-11
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    相关资源
    最近更新 更多