中止,终止还是退出?


112

这三个之间有什么区别?在无法正确处理的异常情况下,我应该如何结束程序?


3
这不是重复的,而是具有良好答案的子集 stackoverflow.com/questions/397075/…而且它也被标记为C ++!
艾莉·凯瑟曼

std::abort如果无法在析构函数中解决异常,则是合理的。
丹尼尔(Daniel)

1
欲了解更多有关信息,std::terminate请参阅安杰出色的这些C ++篇博客:akrzemi1.wordpress.com/2011/09/28/who-calls-stdterminateakrzemi1.wordpress.com/2011/10/05/using-stdterminate
辖施耐德

Answers:


3

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

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

8
@Neil:基本上同意,但是应该报告并重新抛出程序无法处理的异常。让应用崩溃。
John Dibling 2010年

13
为了确保堆栈展开,您应该始终抓住main。但是我会从陷阱中重新抛出。由于某些操作系统具有在调试中进行编译的能力,因此可以自动调用调试基础结构。
马丁·约克

5
即使是顶级处理程序也没有捕获到的异常,可以调用系统报告功能,该功能转储过程并上载异常报告以引起开发人员的注意,例如Windows错误报告,Mac OS X错误报告和iPhone应用程序错误日志。
JBR威尔金森

6
@John让我感到惊讶的原因是,尽管从实际实现异常的角度来看这是完全合理的,但它打破了抽象“将异常“传播到堆栈”,直到找到合适的处理程序(或终止为称为)。泄漏抽象虽然通常是不可避免的,但在遇到时一定令人惊讶。
泰勒·麦克亨利

11
-1,因为这不能回答一半的问题。“[?中止,终止或退出]什么是之间的区别”这是一个更好的答案:stackoverflow.com/a/397081/353094stackoverflow.com/a/2820407/353094是一个很好的答案。
leetNightshade 2015年

149
  • abort表明程序“异常”结束,并引发POSIX信号SIGABRT,这意味着将调用您为此信号注册的任何处理程序,尽管在两种情况下程序仍将终止后缀。通常,您会abort在C程序中使用它来退出意外错误情况,在这种情况下错误很可能是程序中的错误,而不是诸如输入错误或网络故障之类的错误。例如,abort如果逻辑上永远不应该在数据结构中发现NULL指针,则可能会发生这种情况。

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

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

在C ++中,通常最好避免调用abortexit出错,因为最好抛出异常,让代码进一步进入调用堆栈,以决定是否结束程序是合适的。是否使用exit成功取决于具体情况-在s中的return语句以外的其他地方结束程序是否有意义main

std::terminate即使在C ++中,也应被视为最后的错误报告工具。问题std::terminate在于终止处理程序无权访问未处理的异常,因此无法知道它是什么。通常,将整个main打包在一个try { } catch (std::exception& ex) { }块中通常要好得多。至少然后您可以报告有关派生自的异常的更多信息std::exception(当然,不是派生自的异常std::exception最终仍将无法处理)。

包装mainin 的主体try { } catch(...) { }并不比设置终止处理程序好多少,因为您同样无法访问有问题的异常。编辑:根据尼尔·巴特沃思(Neil Butterworth)的回答,这样做的好处是,在这种情况下,堆栈是未缠绕的,对于未处理的异常,这是不正确的(有点令人惊讶)。


10
您可以使用C ++ 11信息更新此答案吗?似乎现在有方法可以在catch(...)和终止处理程序中获取异常。
Klaim

1
在C ++中,终止处理程序确实可以通过来访问异常std::current_exception()。在此处查看示例:akrzemi1.wordpress.com/2011/10/05/using-stdterminate
anorm

可以获取当前异常并不重要,因为您无法对其进行检查。您所能做的就是重新扔掉它。
seattlecpp

2
@seattlecpp,您可以将其扔回并获取对它的引用,然后可以对其进行检查
gpeche

16

std :: abort和std :: exit(还有更多:std :: _ Exit,std :: quick_exit)只是较低级别的函数。您可以使用它们来告诉程序您希望其确切执行的操作:要调用的析构函数(以及是否调用),要调用的其他清理函数,要返回的值等等。

std :: terminate是更高级别的抽象:(运行时或您自己)调用它来指示程序中发生了错误,并且由于某种原因无法通过引发异常进行处理。当异常机制本身发生错误时,通常会发生这种情况,但是当您不希望程序继续超出给定错误时,可以随时使用它。当我在帖子中调用std :: terminate时,我整理了情况的完整列表。没有指定std :: terminate做什么,因为您可以控制它。您可以通过注册任何功能来配置行为。您的局限性在于该函数无法返回到错误站点,并且无法通过异常退出,但是从技术上讲,您甚至可以在内部启动消息泵。有关您可以在其中执行的有用操作的列表,请参阅我的其他文章

特别要注意,在由于无法处理引发的异常而调用std :: terminate的上下文中,std :: terminate被视为异常处理程序,您可以检查异常是什么并使用C ++进行检查11使用std :: rethrow_exception和std :: current_exception。这都是我的帖子


如果程序由于系统信号而终止,是否建议使用清理处理程序?例如,无效的存储器访问导致生成SIGSEGV信号。在这种情况下,让程序终止并拥有核心文件或注册信号处理程序来进行清理,这是一件好事吗?与处理std :: terminate时进行清理相比,在处理系统信号时是否需要进行清理?
卡蒂克·特里维克拉姆

12

quick_exit()

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

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

注意:MSVC ++直到2015版才支持quick_exit()


4
  • 终止使您可以注册调用时将发生的情况。应该是其他两个之一。
  • exit是允许指定退出状态的常规退出。由at_exit()注册的处理程序运行
  • 中止是异常退出。唯一运行的是SIGABRT的信号处理程序。

4
  • 当发生无法处理的异常时,将自动调用终止()。默认情况下,terminate()调用abort()。您可以使用set_terminate()函数设置自定义句柄。

    abort()发送SIGABRT信号。

    exit()不一定是一件坏事。它成功退出应用程序,并以LIFO顺序调用atexit()函数。我通常不会在C ++应用程序中看到这种情况,但是,在很多基于Unix的应用程序中却会看到它在最后发送退出代码的情况。通常,exit(0)表示应用程序已成功运行。


8
不成功!在Unix和DOS中,exit(0)表示成功,传递给exit()的任何其他值表示失败,而不是相反!
理查德·巴雷尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.