【讨论】关于ASSERT断言,小弟我从不使用

【讨论】关于ASSERT断言,我从不使用。
ASSERT也许是一个很好的东西,断言一个必须成立的值。

但是我从来没有使用过,而是一直使用“老套”的返回值的方法,原因有以下几点:

1.   ASSERT不能保证release下不出问题。

一个程序,里面可能会有各种各样的错误,一个十全十美的应用程序,是不可能的,毕竟人不是机器。这个时候,微软就提供了一个叫ASSERT的宏来判断一个值是否为假,并且在MFC源代码里面大肆狂用。这个宏很不错,让大家在DEBUG下能判断出假值。但是release下就判断不了了,当然你可以使用assert()函数,不过我们只讨论ASSERT宏。

有人说,只要DEBUG下断言成功了,RELEASE下就不会出错了。我们仅仅是希望如此而已。举一个例证明一下,内存溢出是所有会写代码的人都会遇到过的问题。你断言成功了,并不代表你内存不会溢出。这时,内存被踩了,谁都无法辨认,当然ASSERT它也不能。这个时候你的程序会继续向下执行,可能在很久之后才会出现错误。这无疑对你查找溢出点增加了很多难度。

如果你不是断言,而是使用的错误判断,很可能就在那一行代码就是查出错误,因为断言只能判断真假,而你的错误判断可以五花八门千变万化,并以错误码返回。当然可能有朋友会说这样会浪费性能,是,不过我更愿意些。

如果要继续举例,可以举出很多来。

2.   使用ASSERT提供的接口,我向来认为不好。

为什么要写这篇讨论,是因为我在网上看到了一们兄台的BLOG,其中有对ASSERT的讨论。http://www.cppblog.com/darkdestiny/archive/2006/07/15/10101.aspx其中有一段话让我想写这篇贴子。“因为我们写函数(接口)的目的,是希望能被正确的调用,而不是胡乱(导致局部或者整体状态混乱)的使用(为此我们居然要将assert写成错误处理的形式,以容忍各种白痴的调用行为).”

我不这样认为,我认为一个接口的提供者应该考虑到各种情况并且能够适应各种情况,这样的接口才是一个优秀的接口,也就是说随便你怎么折磨它都行。当然一个优秀的程序员,是应该仔细按照文档来编写代码,但是谁也不想一运行程序就“当”的一下弹出来错误吧。如果是MFC,至少还有代码可供你参考,你的接口如果没有代码,那别人很难知道是什么错误,因为ASSERT错误不会告诉什么值错了。更不用说RELASE版了,程序运行后会发生什么事,没人能知道。

这个时候如果你有错误返回值,那这一切都完美的解决了。开发人员可以一看返回值就知道是出了什么错误,这样多好,至少我这样觉得。


3.   目前看来,没有什么程序是必须必须要执行下去,而不能返回的。

ASSERT的作用就是在DEBUG里面帮你判断,RELASE里面不管你,也就是在DEBUG里面,值一定要正确,然后执行下去,RELEASE里面无论有不有值程序都将执行下去。我想,应该不会有什么函数是要求不管有不有错误都必须执行下去吧。难道就不能给出一个返回值来告诉作者哪里出错了吗?

在此我置疑MFC里面那大篇大篇的ASSERT。


4.   上面的都是我的一些看法和观点,可以比较狭隘和偏执。希望大家热烈讨论,如果觉得我不对,请说出使用它的理由来,并举例说明,谢谢。我也很希望知道是我自己错了,一般还是不要怀疑微软的东西比较好。

------解决方案--------------------
Up
我也从不使用。。。。。。
------解决方案--------------------
release 下你可以使用VERIFY
------解决方案--------------------
ASSERT用于对调试器辅助作用,偏于方便的定位错误。
------解决方案--------------------
“有人说,只要DEBUG下断言成功了,RELEASE下就不会出错了。”
就算是支持使用ASSERT,这种断言也是不成立的。那么lz从这句话推出不支持使用ASSERT的结论是不是有点没意义?

ASSERT本来就是在DEBUG的时候用的,楼主非要说ASSERT在Release版中没用,所以ASSERT没用,这个是不是不太准确?

另,ASSERT本身是帮助调试,并不是说一定就能保证调试结果,如果承认ASSERT的辅助作用,却因为ASSERT没有“完全的除错”能力就断定不用他,我觉得是一叶障目了。
------解决方案--------------------
“难道就不能给出一个返回值来告诉作者哪里出错了吗?”

类似的还有try...catch呢。

呵呵,使不使用是个人习惯问题罢了,一定要说不好,就有失偏颇了

------解决方案--------------------
这个命题让我想起了以前的goto之争。

楼主的意思大概可以如下归纳(不知道我有没有理解错误)
1.ASSERT的效果有限
2.ASSERT有替代的方式
3.ASSERT的方式不友好(谁也不想一运行程序就“当”的一下弹出来错误吧)

我认为是楼主对ASSERT的作用的误解造成的。
请注意ASSERT不是容错的处理方式,它是为了方便调试错误、判断出错原因的。
我从不指望出现ASSERT后程序还能正常运行。

ASSERT确实可以有其他的方式来替代它,不过在尽可能减少代码量的条件下,大多数情况使用ASSERT比用其它方式更方便判断错误的原因(从这一点上讲有点像goto了)

ASSERT的作用就是在DEBUG里面帮你判断,RELASE里面不管你。这是用法错误,使用ASSERT的原则是不干扰程序运行流程才是对的,之所以会出Debug和Release不同的原因是因为你的ASSERT的用法干扰程序运行流程。

综上所述,ASSERT你可以不用,但是没必要把它一竿子打死。
------解决方案--------------------
ASSERT 是为了便于方便调试错误而产生的

假如你一个函数有多处地方返回了错误,那么调用这个函数的人他就必须单步调试才知道这个错误具体是在函数的什么位置,但是使用ASSERT 不需要单步调试,就知道具体位置在什么地方。这样不是更加快捷、准确吗?而且当你的函数里面又调用了其他的函数,而这个其他的函数也使用返回值的话,你猜猜看,你能很快知道函数出现错误的地方吗?

使用返回值还有一个问题,就是当你的程序没有任何执行结果的时候,你没法判断是因为调用程序方法有错误,还是这个程序在正确执行时确实是没有结果的。


还有你说的一个优秀的接口应该能够容忍所有的错误。
假如一个程序员调用你的接口,可是他确实是不小心的违反了调用规则,简单的就是他在调用接口的时候并没有检测传入参数的合法性,或者传出参数的合法性,如果你的接口容忍了它这个错误,那么程序员就因此而大意了,结果程序执行的结果当然就不是他想要的结果了(有可能就是没有结果,因为你不管什么都返回了,相当于没有调用),他就迷惑了,到底我的程序有错误,还是程序执行确实就是这样?
------解决方案--------------------
真是无话可说,每个人的思维方法不一样,想问题的思路,结果也不一样。。。
------解决方案--------------------