【问题标题】:Questions regarding the usage of set_terminate关于 set_terminate 的使用问题
【发布时间】:2020-08-31 01:42:15
【问题描述】:

我有下面的例子。 (我的实际项目是一个多线程项目,我为所有项目设置了终止处理程序。)我有几个问题。

  1. 我的终止处理程序没有做任何花哨的事情。它只是说发生了错误并退出。我读到添加处理程序是一种好习惯。为什么会这样?在这种情况下我真的需要吗?

  2. 如果我没有处理程序,我会得到抛出的异常类型。 terminate called after throwing an instance of 'char const*' 但是当我使用处理程序时,我无法得到它。即使我使用 current_exception,我也无法获得异常的类型。 (这里显然是 char*,但在我的情况下,它可能是任何东西,所以我无法正确捕捉。即使我使用 catch{...},消息和类型也会丢失)。反正有没有得到消息。如果不是消息,至少我可以得到抛出的异常类型吗?

// set_terminate example
#include <iostream>
#include <exception>
#include <cstdlib>
using namespace std;

void myterminate () {
  cerr << "terminate handler called\n";
  abort();  // forces abnormal termination
}

int main (void) {
  //set_terminate (myterminate);
  throw "TEST";  // unhandled exception: calls terminate handler
  return 0;

【问题讨论】:

  • 如果捕捉到异常,std::terminate 处理程序将不会被调用。 demo
  • 是的,没关系。我说的是获取未经处理的异常的类型
  • 如果你想要你应该处理异常的类型。我怀疑使用terminate_handler 作为正确异常处理的替代品是一种好习惯。也许在一些晦涩难懂的嵌入式环境中,安装try..catch 被认为过于昂贵......但是......不......
  • 同意。就我而言,它是一个多线程系统,我不想对线程使用的每个方法进行尝试捕获。所以我对它们中的每一个都使用了 terminate_handler。如果我不使用它,我会得到异常类型,但如果我使用它,我不会得到类型。
  • 如果您在每个线程中安装terminate_handler,为什么不以try 启动线程函数并以catch 结束它以显示您捕获的内容?如果您仍然希望异常终止应用程序,您可以重新抛出或直接终止,〜同样的效果。如果您在许多地方以不同的方式分派线程,您可以将其包装在一个函数模板中,而不必键入它。

标签: c++11 exception terminate throw terminate-handler


【解决方案1】:

如果您可以忍受&lt;cxxabi.h&gt;1 所暗示的可移植性限制, 那么你可能对下面的backstop() terminate-handler 没问题:

ma​​in.cpp

#include <iostream>
#include <exception>
#include <stdexcept>
#include <cstdlib>
#include <cxxabi.h>

void backstop()
{
    auto const ep = std::current_exception();
    if (ep) {
        try {
            int status;
            auto const etype = abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), 0, 0, &status);
            std::cerr << "Terminating with uncaught exception of type `" << etype << "`";
            std::rethrow_exception(ep);

        } catch(const std::exception& e) {
            std::cerr << " with `what()` = \"" << e.what() << "\"";
        } catch(...) {}
        std::cerr << std::endl;
    }
    std::abort();
}

int main(int argc, char *argv[])
{
    std::set_terminate(backstop);
    if (argc > 1) {
        throw argv[1];
    } else {
        throw std::runtime_error("I am too tired to carry on");
    }
    return 0;
}

这将始终报告未捕获异常的类型,如果该类型源自 std::exception,它也会报告那个异常的what()。例如

$ g++ --version
g++ (Ubuntu 9.3.0-10ubuntu2) 9.3.0
...
$ g++ -Wall -Wextra -pedantic main.cpp; ./a.out Whoops!
Terminating with uncaught exception of type `char*`
Aborted (core dumped)

$ clang++ --version
clang version 10.0.0-4ubuntu1
...
$ clang++ -Wall -Wextra -pedantic main.cpp; ./a.out
Terminating with uncaught exception of type `std::runtime_error` with `what()` = "I am too tired to carry on"
Aborted (core dumped)

请注意,您可能会避免致电 set_terminate(backstop) - 可以想象,这可能是 在一个大而复杂的程序中取消了其他地方 - 并确保任何 转义main 的主体的异常被捕获在function try-block 中,即 将main 替换为:

int main(int argc, char *argv[]) try
{
    if (argc > 1) {
        throw argv[1];
    } else {
        throw std::runtime_error("I am too tired to carry on");
    }
    return 0;
}
catch(...) {
    backstop();
}

这个程序的行为和以前一样。


[1] 你至少会拥有 g++、clang++、icc;你不会有 MS C++

【讨论】:

  • 我们在这里讨论终止处理程序,所以这不是问题,但对于其他人在谷歌搜索时发现此代码abi::__cxa_demangle() 请注意,返回的指针需要传递给free()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-13
  • 2020-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多