Code to crash intentionally
Possible Duplicate:
What is the easiest way to make a C++ program crash?
我经常在我们的代码库中看到一个构造,在这个构造中,程序以某种方式进入无效状态,代码会故意出错,只是为了强制崩溃。通常是这样的:
1 2 3 4 5
| if(<something is wrong>)
{
int *ptr = NULL;
*ptr = 0;
} |
这当然会导致空引用异常,并以不可恢复的方式崩溃程序。我只是想知道这是不是最好的方法?首先,它读起来不好。如果不加评论,您可能不会意识到这里发生的崩溃是有意的。其次,几乎没有办法从中恢复过来。它不会引发异常,因此不能由其他代码处理。它只是杀死了程序,没有办法回溯。它也没有提供太多的线索来解释为什么它会在这里坠毁。它将在所有的构建中崩溃,不像,比方说,断言。(我们确实有一个非常健壮的断言系统可用,但在这种情况下并不总是使用它。)
这是我们在各地使用的风格,我不可能试图说服任何人。我只是好奇这在这个行业有多普遍。
- 为什么不直接使用abort()?
- assert( !() );
- 我怀疑原始程序员的意图是使程序在生产环境中运行时"不可恢复地"失败,或者导致调试程序中断(如果有)。我不喜欢这种结构,但我见过有人认为这是实现这种效果的唯一"可靠"跨平台方法。我个人不会用它。
- 那太可怕了。如果你知道程序有错误,但你不知道为什么,你应该扔掉任何你认为有助于解决问题的东西。在没有任何线索的情况下使程序崩溃的是牛仔编程。
- C++中没有"空引用异常"之类的东西。
- @Robbiedee:"牛仔节目"和"进攻性节目"一样吗?-)
- 听起来问题更多的是"我如何教我的大学如何编码?"(因为我认为每个人都可以承认他们做的不对)
- 没有人希望代码在Live中被忽略,但是让它安静地崩溃是不可能的。想象一下,一些糟糕的支持BOD试图向客户解释这一点:"抱歉,它有时会崩溃,但我们不知道为什么"。我想顾客最终会走…
- 我应该补充一点,这在几个不同的平台上运行(所有当前的游戏机),因此,某些特性(如abort()可能不是所有系统上的跨平台兼容)。我们是一家知名的大公司,我是新来的,所以我倾向于相信他们的话,事情是有原因的。但我还没有听到一个很好的解释。
- @凯瑞克:或者不管叫什么。我来自Java背景,所以"null引用异常"是我习惯于调用它。我想从技术上讲,这不是一个"例外",否则我会抓住它,不会有问题…
你不能故意"崩溃"一个程序,因为根据它的定义,崩溃是当一个程序出错并且不能确定地运行时。
终止执行的标准方法是通过std::terminate;通常实现这一点的方法是调用std::abort,它针对进程发出一个不可阻塞的信号(自动导致std::terminate),并导致许多操作系统产生一个核心转储。
- 不是反过来吗?std::terminate调用std::abort,然后发出信号等。
- @丹尼尔:不,我不这么认为。然而,我在标准中发现了一些额外的信息:未捕获的信号是否导致堆栈展开通常是未知的,但是调用EDOCX1[1]具体来说不会导致任何展开。(也就是说,这正是OP所需要的。)
- 我们实际上不使用C++ STL(或者Boost或任何其他外部库)——这里我们有自己的内部STL,所以在这个代码库中你不会看到EDOCX1 3。甚至连琴弦都不行。我不知道它有没有可用的abort或terminate…
您应该抛出一个异常,它基本上是以一种可控的方式故意导致崩溃。下面是一个例子,在这个问题的帮助下。
1
| throw string("something_went_wrong"); |
更好的是,错误被捕获或修复。断言也是一个不错的选择。
- 最近我编程的Java太多了…无论如何,把这个例子改得更好。
- 不,例外是完全不同的事情。异常的目的是触发应用程序可以从中恢复的异常错误,在这种情况下,目的是在应用程序无法恢复时终止应用程序。
- 未捕获异常的行为与当前行为类似,附加的额外好处是更容易发现,可以提供更有意义的堆栈跟踪,稍后可以通过捕获错误来修复。
- 我特别反对这一点,因为OP提到了他的代码"…不会引发异常,因此其他代码无法处理它。"
我想这是在没有调试的情况下触发核心转储的方法。核心转储然后提供足够的信息来分析问题。在"程序员错误"(或bug)的情况下,这比抛出异常要好,因为堆栈展开不允许您构建合理的核心转储。通过调用std::terminate并预先注册(使用std::set_terminate)一个生成核心转储的函数或类似的函数,可以以更优雅的方式实现类似的效果。有关更详细的解释,请参阅本文。