【问题标题】:Override default unhandled exception behaviour覆盖默认的未处理异常行为
【发布时间】:2015-12-29 16:19:54
【问题描述】:

我有这个代码:

#include <iostream>
#include <exception>

class TestException : public std::exception
{
public:
    char const* what() const throw() override { return msg_.c_str(); }

protected:
    std::string & message() throw() { return msg_; }

private:
    std::string msg_;
};

void ThrowIt()
{
    throw TestException();
}

int main()
{
    ThrowIt();
}

在使用 Visual Studio 编译的 Windows 上的 Release 或 Debug 中运行此程序会导致程序终止,在 Linux 机器上使用 GCC 编译时也是如此,结果是:

在抛出“TestException”实例后调用终止
what(): 中止

一旦捕获到未处理的异常,两者都会终止程序。这种行为是严格的系统特定的还是标准规定的?有没有一种跨平台的方法可以让我将catch 未处理的每个异常重新路由到处理程序,而不仅仅是终止程序?

【问题讨论】:

    标签: c++ c++11 exception-handling g++ visual-studio-2015


    【解决方案1】:

    15.5.1 的 C++11 标准状态:

    [...] 当异常处理机制无法找到抛出异常的处理程序时 [...] std::terminate() 被调用。在没有找到匹配处理程序的情况下, 在调用std::terminate() 之前是否展开堆栈由实现定义。

    所以终止是标准行为,但您是否可以从这种情况中恢复是实现定义的。在任何情况下都不会重新路由异常对象。

    您还可以使用terminate_handler set_terminate(terminate_handler f) noexcept;更改std::terminate()调用的处理函数(typedef void (*terminate_handler)();)并使用terminate_handler get_terminate() noexcept;查看它。

    【讨论】:

    • 编辑std::terminate 处理程序不允许我查看引发的异常,该异常首先导致std::terminate,对吗?
    • @JameyD 是的,这就是您从标准中获得的全部内容。
    【解决方案2】:

    在您的代码中,您有一个未捕获的异常,因为您的异常没有匹配的句柄。 this 的行为在 [except.terminate]

    中有介绍

    在某些情况下,必须放弃异常处理以使用不太微妙的错误处理技术。 [注:这些情况是:
    [...]
    - 当异常处理机制找不到抛出异常的处理程序时(15.3),或 [...]

    然后我们有

    在这种情况下,调用 std::terminate() (18.8.3)。在没有找到匹配处理程序的情况下, 在调用 std::terminate() 之前堆栈是否展开是实现定义的。

    如果您想拥有“顶级”catch 来处理程序中的所有异常(如果没有被捕获),您可以将 main() 中的代码包装在 try...catch 块中。任何未捕获的异常都会根据 [except.handle] 向上移动

    如果在 try 块的处理程序中没有找到匹配项,则继续搜索匹配的处理程序 动态环绕同一线程的 try 块。

    您也可以使用std::set_terminate 更改std::terminate_handler

    【讨论】:

    • 是的,我知道我有一个未捕获的异常,这是该程序的目标。我试图避免catch(...)。如问题中所述,我想知道您是否可以为 catch 块未捕获的异常添加跨平台处理程序。
    【解决方案3】:

    我不确定有什么标准保证,但在 GCC、clang 和 MSVC 的实践中,您可以在终止处理程序中使用 std::current_exception() 来处理异常。像这样:

    #include <stdexcept>
    #include <iostream>
    
    void f()
    {
        try
        {
            std::rethrow_exception(std::current_exception());
        }
        catch(const std::exception &e)
        {
            
            std::clog << "exception: " << e.what() << std::endl;
        }
    }
    
    int main()
    {
        std::set_terminate(f);
        throw std::runtime_error("oh no");
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-04-25
      • 2016-06-04
      • 2017-05-02
      • 1970-01-01
      • 2012-07-09
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      相关资源
      最近更新 更多