什么时候该用assert
—————————————————-
Michael to pongba
有下面2种方法:
方法一:Section *pImageSection = new Section(pImage);
assert(pImageSection);
方法二:略
ps:现在项目组代码用第一方法,并且也不写日志,每一次客户端down了,定位问题都要很久,让人很崩溃。并且到处都是assert。
我个人认为,用assert的地方,是比较严重的错误,甚至不能够让程序再运行下去。
如果到处用asset也太残忍了,有的时候应该温柔的跳过,然后写日志,返回。告诉我哪里运行失败了。
—————————————————-
下面是我对这个问题的回答:
首先需要指出一个非常重要、讨论前必须明确的问题,assert一般不应该直接用,而应该包装一下,比如微软就有ASSERT宏,可以跟踪line file这些有用信息,另外可以通过条件编译取消ASSERT。每次定位很久,只能说这种编程common sense还没有建立起来。
原文虽然说得很简单,其实涉及了几个方面,一个是版本管理发布,一个是错误处理机制,一个是如何写日志,我们一个个讨论。
首先是什么情况下用ASSERT,什么情况下应该处理wrong case?
一个成熟的代码里面,大概有百分之三十到七十的代码都是为了查错,fault tolerance。比如你写一个API或者对外使用的函数,别人要调用,你要确保传入的指针不为空,传入的参数合法,这时候都不应该,注意是不应该使用ASSERT,因为这些情况out of your control。
什么情况可以使用ASSERT,应该是那些绝少发生的例子,而且你可以控制的那些代码段落,比如Object* p = new Object,返回空指针,这种情况下多半是内存申请出错,即使你容错了,后面的逻辑也不会正常,这时候就应该停止运行报错了。还有就是你的内部函数(注意是你程序的内部哦),因为内部函数的代码责任其实是你自己的,你传错参数只能说水平太差怨不得别人。也许有人会说,同组里别的程序员万一也调用了这个函数怎么办?这种情况当然是会有的,其实也没法避免,但可以用ASSERT以及Code review这些手段来规范,同一个程序组里面的问题属于内部矛盾好解决多了。
所以,大的原则可以是这样:内部函数尽量简化容错机制,稍微苛刻一些,而对外接口则尽量容忍,出错处理也要温柔。
第二个问题,ASSERT该怎么写?
我已经提到,不要直接使用assert,最好包装一下,加入#ifdef _DEBUG这种条件编译选项,保证Release版本不弹出ASSERT。这里其实也涉及到版本管理问题,一个商业产品发布一般包含两个版本(Release版以及Debug checked版本),即使是Windows操作系统也是如此。在Release版本要Disasble assert,这时候如果出错可以用后面的Crash Dump机制捕捉跟踪,而且要说明的是Release版本一样要附带PDB文件(或者Linux同类文件),保证Crash Dump可以定位。Debug版本也要发给用户,用户可以通过它返回更详细信息。每个Build出来的Release、Debug都应该妥善备份,将来客户提交Bug,对应版本以及PDB,就可以准确定位,不会出现很难差错的现象。
另外也可以加入日志log选项。在这里跑一下题,日志记录也是个大问题,要考虑多线程以及性能问题,其实不是加入日志系统就万事大吉了,说句难听的,对于那些2B Number One的人来讲,任何一个好东西都可能被他们用到烂。一般ASSERT跑出来,对于客户来说就等同于Crash了,所以可以参考一下Google的Crash Report开源项目,比如Windows下可使用Crash Dump机制来捕捉崩溃时调用栈,这样即使Fail Soon Fail Fast也不会很难看。这些手段都是common sense的东西,一个正常的软件开发公司应该积累下这些代码财富才对。
原文地址:http://www.cnblogs.com/lua5/archive/2010/12/05/1896756.html