【问题标题】:abort, terminate or exit?中止、终止或退出?
【发布时间】:2011-02-18 16:51:01
【问题描述】:

这三者之间有什么区别,如果出现我无法正确处理的异常,我应该如何结束程序?

【问题讨论】:

标签: c++


【解决方案1】:
  • terminate 让您可以记录调用它时会发生的情况。应该是其他两个之一。
  • exit 是允许指定退出状态的正常退出。 at_exit() 注册的处理程序正在运行
  • abort 是异常退出。唯一运行的是 SIGABRT 的信号处理程序。

【讨论】:

    【解决方案2】:

    我的建议是不要使用它们中的任何一个。相反,catch 是您无法在main() 中处理的异常,而从那里只是return。这意味着您可以保证堆栈展开正确发生并调用所有析构函数。换句话说:

    int main() {
        try {
           // your stuff
        }
        catch( ... ) {
           return 1;    // or whatever
        }
    }
    

    【讨论】:

    • @Neil:基本同意,但是程序无法处理的异常应该报告并重新抛出。让应用崩溃。
    • 为了确保堆栈展开,您应该始终在 main.catch 中捕获。但我会从接球中重新抛出。如果您在调试中编译,某些操作系统能够自动调用调试基础结构。
    • 即使顶级处理程序也无法捕获的异常可能会调用系统报告工具,该工具会转储进程并上传异常报告以供开发人员注意,例如 Windows 错误报告、Mac OS X错误报告和 iPhone 应用程序错误日志。
    • @John 让我感到惊讶的原因是,尽管从异常的实际实现方式来看它非常有意义,但它打破了异常“向上传播”的抽象,直到找到合适的处理程序(或调用终止)。泄漏的抽象虽然通常是不可避免的,但在遇到时必然会令人惊讶。
    • -1 因为这不能回答一半的问题。 “[中止、终止或退出有什么区别?]”这是一个更好的答案:stackoverflow.com/a/397081/353094 另外stackoverflow.com/a/2820407/353094 也是一个很好的答案。
    【解决方案3】:
    • abort 表示程序“异常”结束,并引发 POSIX 信号 SIGABRT,这意味着将调用您为该信号注册的任何处理程序,尽管程序在任何一种情况下仍将终止后记。通常您会在 C 程序中使用abort 来退出意外错误情况,其中错误可能是程序中的错误,而不是诸如输入错误或网络故障之类的错误。例如,如果发现某个数据结构中包含 NULL 指针,那么您可能会abort,而这在逻辑上永远不会发生。

    • exit 表示程序“正常”结束,尽管这仍可能表示失败(但不是错误)。换句话说,如果用户提供了无法解析的输入,或者无法读取文件,您可能会使用错误代码 exit。退出代码 0 表示成功。 exit 还可以选择在程序结束之前调用处理程序。这些是使用atexiton_exit 函数注册的。

    • std::terminate 是在出现未处理异常时在 C++ 程序中自动调用的内容。这本质上是等同于abort 的C++,假设您通过抛出异常来报告所有异常错误。这将调用由std::set_terminate 函数设置的处理程序,默认情况下,该函数只调用abort

    在 C++ 中,您通常希望避免在出错时调用 abortexit,因为您最好抛出异常并让代码进一步在调用堆栈中决定是否适合结束程序。您是否使用exit 来获得成功是一个环境问题——在main 中的return 语句以外的地方结束程序是否有意义。

    std::terminate 应该被视为最后的错误报告工具,即使在 C++ 中也是如此。 std::terminate 的问题在于终止处理程序确实 not 有权访问未处理的异常,因此无法判断它是什么。通常最好将整个 main 包装在 try { } catch (std::exception& ex) { } 块中。至少,您可以报告有关源自std::exception 的异常的更多信息(当然,并非源自std::exception 的异常最终仍将未处理)。

    main 的主体包装在try { } catch(...) { } 中并不比设置终止处理程序好多少,因为您再次无法访问相关异常。 编辑:根据 Neil Butterworth 的回答,在这种情况下,堆栈是展开的,这对于未处理的异常来说是不正确的(有点令人惊讶)。

    【讨论】:

    • 你能用 C++11 信息更新这个答案吗?似乎现在有办法在 catch(...) 和终止处理程序中获取异常。
    • 在 C++ 中,终止处理程序确实可以通过std::current_exception() 访问异常。请参阅此处的示例:akrzemi1.wordpress.com/2011/10/05/using-stdterminate
    • 获取当前异常并不重要,因为您无法检查它。你所能做的就是重新扔它。
    • @seattlecpp 您可以重新抛出它并捕获对它的引用,然后您可以对其进行检查
    【解决方案4】:
    • terminate() 被自动调用 当发生不能 被处理。默认情况下,终止() 调用 abort()。您可以设置自定义 使用 set_terminate() 函数处理。

      abort() 发送 SIGABRT 信号。

      exit() 不一定是坏事 事物。它成功退出 应用程序,并调用 atexit() 按 LIFO 顺序运行。我不 通常在 C++ 中看到这个 应用程序,但是,我确实在 许多基于 Unix 的应用程序 最后发送退出代码。 通常一个 exit(0) 表示一个 应用程序成功运行。

    【讨论】:

    • 不成功!在 Unix 和 DOS 中,exit(0) 表示成功,传递给 exit() 的任何其他值都表示失败,而不是相反!
    【解决方案5】:

    std::abort 和 std::exit(以及更多:std::_Exit、std::quick_exit)只是较低级别的函数。您可以使用它们来告诉程序您希望它做什么:调用什么析构函数(以及 if),调用什么其他清理函数,返回什么值,等等。

    std::terminate 是更高级别的抽象:它被调用(由运行时或您)指示程序中发生了错误,并且由于某种原因无法通过抛出异常来处理。这样做的必要性通常发生在异常机制本身发生错误时,但是当您不希望程序继续超出给定错误时,您可以随时使用它。当 std::terminate 被称为 in my post 时,我编译了完整的情况列表。没有指定 std::terminate 做什么,因为您可以控制它。您可以通过注册任何功能来配置行为。您的限制是该函数无法返回错误站点,并且无法通过异常退出,但从技术上讲,您甚至可以在内部启动消息泵。有关您可以在里面做的有用事情的列表,请参阅my other post

    特别注意,在 std::terminate 由于无法处理的抛出异常而被调用的上下文中,std::terminate 被视为异常处理程序,您可以检查异常是什么并通过使用来检查它C++11 使用 std::rethrow_exception 和 std::current_exception。都在my post

    【讨论】:

    • 如果程序因系统信号而终止,是否建议使用清理处理程序?例如,无效的内存访问会导致产生 SIGSEGV 信号。在这种情况下,让程序终止并拥有核心文件或注册一个信号处理程序来进行清理是不是很好?与处理 std::terminate 时进行清理相比,在处理系统信号时进行清理是否有任何顾虑?
    【解决方案6】:

    quick_exit()!

    如果您的程序是多线程的,那么调用exit() 很可能会导致崩溃,因为全局/静态std::thread 对象将被尝试在不退出其线程的情况下进行破坏。

    如果你想返回错误代码并正常退出程序(或多或少),请在多线程程序中调用quick_exit()。 对于异常终止(您无法指定错误代码),可以调用abort()std::terminate()

    注意:quick_exit() has not been supported by MSVC++ 直到 2015 版。

    【讨论】:

    • 这是有道理的。但是,调用未加入线程的 dtor 将调用 std::terminate,因此程序不一定会“崩溃”。我认为标准这样做是因为它不能加入 dtor。因此,在多线程程序中,在我看来 std::terminate 是 ctors/dtors 和 std::quick_exit 其他地方的首选方法。请确认...
    猜你喜欢
    • 1970-01-01
    • 2019-10-05
    • 2014-04-10
    • 2011-04-05
    • 2017-07-03
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多