为什么我应该使用断言?

我从来没有断言的想法 – 你为什么要使用它们?

我的意思是,假设我是公式驱动者,所有的断言都是安全带,头盔等等。

testing(在debugging中)都可以,但现在我们要做赛车(发布)! 我们是否应该放弃所有的安全措施,因为testing时没有问题?

我永远不会删除它们。 我认为大多数声称去掉可比较的断言的人绝不会描述他们的代码或断言是绝对的stream离失所。 我从来没有见过任何真正的性能优势,特别是在80/20规则。

那么,我是不是也错过了这个观点,或者有人可以告诉我,为什么我要使用断言? 顺便说一句,我正在使用unit testing。

首先,性能差异可能是巨大的。 在一个项目中,我们的断言实际上导致了3倍的放缓。 但他们帮助我们发现了一些真正烦人的错误。

这正是重点。

断言在那里帮助你捕捉错误。 而且由于它们在发行版本中被删除,所以我们可以承担很多的function,而不用担心性能。 如果你不是在那里做任何失败的断言,他们变得毫无价值,所以我们不妨删除它们。

即使捕获错误并抛出exception也不是真正的解决scheme。 程序逻辑是有缺陷的,即使我们处理这个exception,程序仍然是坏的。

基本上归结为“为什么麻烦捕捉错误,你不能处理?

在开发过程中必须捕捉一些错误。 如果他们滑过testing,并进入客户使用的发布版本,程序就会中断,并且没有任何运行时错误检查可以解决这个问题。

我从来没有断言的想法 – 你为什么要使用它们?

我的意思是,假设我是公式驱动者,所有的断言都是安全带,头盔等等。

是的,这是什么时候使用断言的好例子。 这些是在运行时可能实际发生错误的事情,需要检查哪些事情。 你的公式一个司机可能会忘记一些安全预防措施,如果他这样做,我们希望在任何人受伤之前停止整个事情。

但是,检查发动机是否安装? 我们需要在比赛中检查吗?

当然不是。 如果我们在没有引擎的情况下进入比赛,那么我们就被搞砸了,即使我们发现了这个错误,现在为时已晚。

相反,这是一个在开发过程中必须被捕获的错误,或者根本不是。 如果devise师忘记在汽车中放置引擎,他们需要在开发过程中检测到这个错误。 这是一个断言。 这与开发者在开发过程中是相关的,但之后,这个错误一定不存在,如果是这样的话,我们什么也做不了。

这基本上是差异。 有一个例外是通过处理可以处理的错误来帮助用户。

有一个断言可以帮助 ,提醒你一定不会发生的错误,在产品发货之前必须解决。 错误不依赖于用户input,而是依赖于你的代码做它应该做的事情。

四的平方根决不能评价为三。 错误是根本不可能的。 如果确实发生,你的程序逻辑就会被破坏。 不pipe我们包装多lesserror handling都是无关紧要的,这是在开发过程中必须被捕获的,或者根本不是。 如果我们使用exception处理来检查这个错误并处理它,那么exception将会怎样呢? 告诉用户“程序基本上是坏的,千万别用它”?

来自开发者的电子邮件可能已经实现了。 为什么要把它构build到程序代码中呢? 这是一个不可能发生的问题的例子。 如果是这样,我们必须回去修复这个程序。 没有其他forms的error handling是可能的。

但是有些错误,比如无法打开文件进行阅读,是可能的 。 即使发生这可能是一件坏事,但我们必须承认它可能发生。 所以我们需要处理它,如果它。

断言是为了捕捉不可能发生的错误。

安德鲁·科尼格(Andrew Koenig)过去对运输代码中exception和断言的使用进行了很好的哲学讨论 。 最后, 当程序处于无法挽回的破坏状态时你就会防止做野蛮的事情

因此,我认为,当一个节目发现一些内部状态是无可辩驳的错误时,最好马上结束,而不是让主叫方有机会假装没有错。

如果你愿意的话,我认为应该保留exception,以便在捕捉到exception之后可以做一些合理的事情。 当你发现一个你认为不可能的情况时,很难说出事后会发生什么。

从代码完成2:“对预期发生的情况使用error handling;使用断言来处理永远不会发生的情况。

一个普遍引用的例子是在分母之前检查分母中的零。

您应该从生产代码中剥离断言。 他们在发展过程中,帮助你发现错误。

unit testing不是断言的替代。

因为他们使debugging更容易。

debugging耗时的部分是从您首先发现的症状中追溯到代码中的错误。 写得好的断言将使您注意到的症状更接近实际的代码问题。

一个非常简单的例子就是一个错误,那就是索引超出数组的末尾,导致内存损坏,最终导致崩溃。 从崩溃追溯到违规指数操作可能需要很长时间。 但是,如果您在该索引操作旁边有一个断言来检查索引,那么程序将在错误旁边失败,所以您将能够快速find问题。

从你的文章来看,这听起来像你不是不同意使用断言的想法,而是在debugging中断言,而不是让他们在生产中活跃的想法。

原因是在debugging的时候,你可能希望进程发生灾难性的失败 – 即抛出一个exception并退出,这样就可以解决错误。 在生产中,这可能会影响整个系统,并且只有极less数情况才会出现错误情况。 因此,在生产中,您可能需要logging错误,但保持进程运行。

使用断言可以改变debugging和发布之间的行为。

我同意你的观点,断言不应该在生产代码中被压制 – 很多错误不会在testing环境中暴露出来,重要的是要知道什么时候断言在生产中失败。

他们使你能够testing你的假设。 例如,假设你想计算速度。 你可能会想要断定你的计算小于光速。

断言是为了发展,确保你不会搞砸。

这是一个有争议的话题。 很多人和我一样,实际上更喜欢把它们留在生产代码中。 如果你的程序无论如何都要进入杂草,那么你也可以在那里有断言,这样你的客户至less可以给你行号和文件名(或者你configuration断言的任何信息或动作)。 如果你断言,所有的客户可能会向你报告是“它坠毁”。

这意味着你可能不应该在你的断言检查中进行昂贵的操作,或者至less在configuration文件中查看是否会导致性能问题。

断言是重要的,而我认为是非常宝贵的。 如果你想用algorithm2()replacealogrihm1(),你可以使用它们并且在结果相等时断言。 然后你可以逐渐淘汰algorithm1()

断言也适用于您可能会快速进行的一些更改,但在系统状态的上下文中不太确定。 设置断言你做的假设,会很快帮助你指出这个问题,如果有的话。

在发布中,是否应该通过使用macros或者类似的东西来剥离断言是值得商榷的,但是到目前为止我所做过的项目中已经做了这些工作。

在代码完整是一个类似的东西。 每当你写一个如果没有其他的东西,你可能会错过一些东西。

这就像这个代码

int i = 1 i = i++ 

如果我在后面的代码中是负面的,那么常见的程序员就不会想到会发生什么。 你的代码产生一个溢出的机会有点小,像java这样的语言会从max int跳到min int,你会得到一个非常大的负数。 这是你通常说的所有情况。 呃这永远不会发生。 但是,如果发生这种情况,你的计划是什么? 所以,如果你知道有什么东西是你认为永远不会发生的testing或反对它,并把一个错误的断言,否则将永远不会发生,而不是编程else语句。 这样你的程序就会在你不确定它正在做什么的时候完全崩溃。 在生产代码中,应该有些不同的东西,比如通知用户,维护者然后退出。

断言的另一个用法是契约驱动devise。 你指定一个与你的界面的合同,根据你在程序中的位置你断言你的input,但更多的导入你断言你的输出两个。

我同意你的观点,在生产代码中禁用断言使得断言相当无用。 而在java vm中,默认的断言在我看来是危险的。

断言只能用于在开发期间检查在发布期间不需要的条件。

下面是如何在开发中使用断言的一个非常简单的例子。

 A(char* p) { if(p == NULL) throw exception; B(p); C(p); } B(char* p) { assert(p != NULL); D(p); do stuff; } C(char* p) { assert(p != NULL); D(p); do stuff; } D(char* p) { assert(p != NULL); do stuff; } 

而不是调用“if(p == NULL)throw exception” 5次,您只需调用一次,因此在inputB(),C()和D()时,您已经知道它不是NULL。 否则,断言将在开发阶段退出,因为你“改变了代码!” 不是因为“用户的input”。

这可以使代码在发行版本中运行得更快,因为所有你需要做的就是调用带有“-DNDEBUG”的gcc,这样所有的断言都不会被编译,所有的“不必要的检查”都会在可执行文件中被删除。

在我工作过的很多项目中,断言是通过一个在Debug和Release中具有不同行为的自定义macros来完成的。

在“debugging”中,如果条件为false,则代码中的该位置将启动debugging器。

在Release中,错误被写入日志文件,给用户一个警告,然后系统尝试保存未保存的数据。 处于未知状态可能会失败,但值得尝试。

我已经写了代码的地方断言明显影响性能启用时。 例如,检查graphics代码在紧密循环中使用的math函数的前置条件和后置条件(平方根函数对其结果进行平方并将其与input进行比较等)。 当然,这是在几个百分点的顺序,但我写了代码,需要这几点。

更重要的是,我写了代码,其中断言使代码的大小有百分之几的差异。 当内存占用是一个问题,在发布代码断言可能是一个不可接受的奢侈。

我主要在开发过程中使用它进行testing。 例如, 这里是我的utf-8库的烟雾testing当我在库代码中进行更改时,我会运行testing,如果引入了一个错误,那么assert会触发。 当然,我可以使用一个完整的unit testing框架,但为了我的目的,assert就好了。

不能抗拒引用“不可或缺的加尔文和霍布斯” 180:

在像这样一座陡峭的山坡前,应该总是给他的雪橇安全检查。
对。
安全带 ? 没有。
信号? 没有。
刹车? 没有。
操舵 ? 没有。
WHEEEEEE

当你做这样的事情时,应该使用断言

 a = set() a.add('hello') assert 'hello' in a 

要么

 a = 1; assert a == 1; // if ram corruption happened and flipped the bit, this is the time to assert 

至于例外,这是你编程处理的东西:

 while True: try: data = open('sample.file').read() break // successfully read except IOError: // disk read fail from time to time.. so retry pass 

大多数情况下,断言发生时重新启动应用程序会更安全,因为您不想处理不可能的情况。 但是,当预期的情况发生(预期的错误(从黑客客户端,networking电话等大部分时间),应该使用例外。

断言应该用于预测程序员使用API​​ /函数/类/其他方式的错误。 这些错误需要在debugging时迅速修复。

对于其他一切,抛出一个exception。

我从来没有在我的代码中使用断言,我恨他们激情。 我明白需要错误检查和处理,但要防止一个错误,通过崩溃你的程序自己的程序崩溃….坦率地说,我没有看到的优势。

在你的代码中留下一个断言,墨菲定律将确保它最终会使你的程序崩溃。 我更喜欢在处理数据之前检查数据并抛出相应的exception,以便像其他exception状态或操作一样处理。 根据我的经验,从用户的立场出发,确定性的行为从长远来看产生了更为稳定的软件。

作为一名软件工程师,当你的程序断言时,你会知道该怎么做,大多数用户会害怕他们破坏了某些东西,最终不会使用你的软件。 所以除非你正在为工程师开发(这是很有可能的),即使如此…

从可用性的angular度来看,断言是可怕的,即使它们不是“应该”发生,我们都知道最终它会…


好的…从所有的评论和火灾我到这里我想我需要进一步解释我的观点,因为它显然是不明白的。

我没有说我没有检查exception情况,奇怪的价值观或者是错误的状态,我只是说我没有使用断言,因为他们试图从最终用户的angular度来closures系统。 大多数现代语言也提供了另一种types安全的方法来处理这些情况,然后当完美的exception可以做到这一点时,我会使用断言,而且非常好。

在我看到的大多数生产代码中,我注意到主要有两种方法来处理这个问题,在整个代码中断言,然后在生产中留下一大堆。 这有真正的趋势,只是closures应用程序的用户,我还没有看到一个断言优雅地失败系统….它只是失败了…繁荣…走了…最终用户只是说“WTF是地址0x330291ff处的断言失败错误!!!“

反之,如果你问我的话,最糟糕的是要把所有被扔出来的东西都藏起来,藏在地毯下面(用空括号看过这些可怕的尝试!)

没有办法将工作,以获得一个良好的稳定系统。 当然,你可以在你的testing代码中使用断言,并把它们全部删除在生产代码中,但是为什么你会把你的安全网删除,因为它是生产。 所有这些检查都会削弱你系统的性能,我会感到非常惊讶的。

build立自己的一个很好的exception处理scheme,并由上帝…把它放在那里,你会得到更有意义的信息我们的系统,如果适当总是在上下文中,而不是有一些深层的库扔断言,因为缺less东西。

在创build图书馆时尤其如此…认为作为图书馆创build者的你可以决定何时closures整个系统,因为抛出的数据出了问题,是非常自私和狭隘的。 让你的图书馆的用户决定什么是非常重要的,它应该保证紧急失败。

所以不…我不使用断言…我使用exception

是的…通常情况下,生产失败的代码很less有我的名字。