在按照契约式编程时,一个函数或方法会首先检查其前置条件是否已满足,然后才会开始处理自己的职责,对吗?目前最常用的两种检查方法是通过assert
和exception
实现的。
assert
只在调试模式下失败。要确保其关键是(单元)测试所有单独的合同前提条件,以查看它们是否实际上失败了。exception
在调试和发布模式下都会失败。这种方式的好处是,经过测试的调试行为与发布行为相同,但它会产生运行时性能损失。
你认为哪个方法更可取?
相关问题请参见此处
在按照契约式编程时,一个函数或方法会首先检查其前置条件是否已满足,然后才会开始处理自己的职责,对吗?目前最常用的两种检查方法是通过assert
和exception
实现的。
assert
只在调试模式下失败。要确保其关键是(单元)测试所有单独的合同前提条件,以查看它们是否实际上失败了。exception
在调试和发布模式下都会失败。这种方式的好处是,经过测试的调试行为与发布行为相同,但它会产生运行时性能损失。你认为哪个方法更可取?
相关问题请参见此处
经验之谈是:当你试图捕获自己的错误时,应该使用断言(assertions),而在试图捕获其他人的错误时,则需要使用异常(exceptions)。换句话说,你应该使用异常来检查公共API函数的前提条件以及任何来自于你系统外部的数据。而对于内部函数或数据则应该使用断言。
断言(Asserts)用于捕捉开发人员犯的错误(不仅是你自己,还有团队中的其他开发人员)。如果用户的错误可能导致这种情况,那么它应该是一个异常。
同样要考虑后果。一个断言通常会关闭应用程序。如果有任何现实的期望条件可以从中恢复,那么你应该使用异常。
另一方面,如果问题只能由程序员的错误引起,则使用断言,因为你希望尽快知道它。异常可能会被捕获和处理,你永远不会发现它。是的,在发布代码中应该禁用断言,因为在那里,如果有最小的机会,你希望应用程序恢复。即使你的程序状态非常糟糕,用户也可能能够保存他们的工作。
assert
是System.Diagnostics.Debug.Assert
,它在Debug版本中只会失败,并且将在Release版本中在编译时删除。 - yoyo我在这里阐述了我的看法:如何验证对象的内部状态?通常,要断言你的声明并对他人的违规行为进行抛出。对于禁用发布构建中的断言,您可以执行以下操作:
当然,在发布构建中,失败的断言和未捕获的异常应该以另一种方式处理,而不是在调试构建中(在那里它只能调用std :: abort)。将错误日志写入某个地方(可能是文件),告诉客户发生了内部错误。客户将能够向您发送日志文件。
在comp.lang.c++.moderated上有一个巨大的线程,关于在发布版本中启用/禁用断言,如果你有几周时间,可以看到对此的意见有多种多样。 :)
与coppro相反,我认为,如果您不确定一个断言在发布版本中是否可以被禁用,那么它就不应该是一个断言。断言是用来保护程序不变量被破坏的。在这种情况下,就客户端代码而言,有两种可能的结果:
你在询问设计时错误和运行时错误之间的区别。
断言是“嘿,程序员,这里出错了”的通知,它们存在的目的是在发生错误时提醒你注意到那些你可能没有注意到的错误。
异常是“嘿,用户,出了点问题”的通知(显然你可以编写代码来捕获它们,以便用户不会被告知),但这些异常是设计为在 Joe 用户使用应用程序时发生的。
所以,如果你认为你可以解决所有的错误,只使用异常。如果你认为你不能......还是使用异常吧。当然,你仍然可以使用调试断言来减少异常的数量。
不要忘记,许多前提条件将是用户提供的数据,所以你需要一个很好的方式来告知用户他的数据有问题。为了做到这一点,你经常需要将错误数据返回到与之交互的部分的调用堆栈中。断言在这种情况下将无用 - 尤其是如果你的应用程序是多层的。
最后,我都不会使用 - 错误码对于你认为会经常发生的错误来说更加优越。:)
对我来说,经验法则是使用断言表达式来查找内部错误,并使用异常处理外部错误。您可以从这里的Greg的以下讨论中获得很多好处。
Assert表达式用于发现编程错误:程序逻辑本身的错误或对应实现中的错误。Assert条件验证程序仍处于定义状态。 “定义状态”基本上是与程序假设一致的状态。请注意,“程序的定义状态”不必是“理想状态”,甚至不是“通常状态”,甚至不是“有用状态”,但稍后会更多关注这一重要点。PS:你可能想查看类似的问题:异常 vs 断言。
我更喜欢第二个。虽然你的测试可能运行得很好,但Murphy说会出现一些意外情况。因此,你不是在实际错误的方法调用处得到异常,而是在深入10个堆栈帧后跟踪出一个NullPointerException(或等效物)。