“ S下,我想出了一个防龙术。” 他不再害怕我们! 它是由龙的翅膀拍打触发的,并发出响亮的警笛,以便所有人都能听到龙的到来。
“这种防御还有其他作用吗?”
“不,为什么?” 我们会被警告!
“是的……被警笛声吞噬了……但是……当我们计划中断时,提醒我们吗?……
问题描述
这种方法并不假装在复杂项目中处理错误的概念。 相反,这是可以用最少的方法完成的示例。
一个好的规范是假定在程序执行期间不应触发assert()。 并且如果在测试应用程序时至少有一个assert()有效,那么您需要将此错误发送给开发人员。 但是,如果应用程序未经过完全测试怎么办? 而assert()对客户有用吗? 向开发人员发送错误? 中止程序? 实际上,这将是应用程序的发行版,而标准的assert()将被禁用。 该系统的内部矛盾也引起了这个问题:应该有很多assert()使其更易于检测错误,但是应该有较少的assert()来减少对用户及其应用程序的干扰。 如果要使用多少应用程序取决于工作的稳定性,并且assert()本质上是无关紧要的(需要更正,但例如允许其继续非常成功地进行工作),我尤其不想“跌倒”。
这些考虑导致需要细化assert()c / c ++。 并定义自己的宏,这些宏扩展了标准assert()的功能-但要添加最少的错误处理。 让这样的宏。
VERIFY_EXIT(条件);
VERIFY_RETURN(条件,返回值);
VERIFY_THROW(条件,例外);
VERIFY_DO(条件){/ *失败块* /};(这些宏也可以不同地调用。例如,VERIFY_OR_EXIT(),VERIFY_OR_RETURN(),VERIFY_OR_THROW(),VERIFY_OR_DO()。或者在较短的版本中则相反。)
首先,这些宏具有针对编译的调试版本和发行版本的实现。 这使他们在程序的发行版本中具有行为。 即 不仅要在测试过程中执行操作,还要与用户一起执行操作。
宏描述
(宏的描述是近似的,也可以使用其他设计。)
1)
VERIFY_EXIT(条件);它检查
条件条件,如果
条件条件为假,则调用标准的assert()(调试版本),并退出当前函数(调试和发行版本)。
2)
VERIFY_RETURN(条件,ReturnValue);它检查
Condition条件,如果条件为false,则调用标准的assert()(调试版本),并通过返回
ReturnValue (调试版本和发行版本)退出当前函数。
3)
VERIFY_THROW(条件,例外);检查
Condition条件,如果条件为false,则调用标准的assert()(调试版本),并引发
Exception (调试版本和发行版本)。
4)
VERIFY_DO(条件){/ *失败块* /};检查
条件条件,如果
条件条件为false,则调用标准的assert()(调试版本),并在宏之后立即执行
故障块或操作(调试版本和发行版本)。
对于所有宏,重要的是:
- 在所有情况下, 条件必须为true才能“传递”宏,为false才能激活最小错误处理的路径。
- 每个宏都实现一些最小的错误处理方法。 对于在测试过程中未检测到但在用户处发生的错误,实施该行为是必要的。 根据实现的不同,您可以通知开发人员客户端发生的错误,但是每种实现都提供了一种从错误中恢复的最小方式。
宏使用模式
当然,最有趣的是熵超人(减少程序错误的英雄)是这些宏的使用。
1)前后条件。
第一个用例是前置条件和后置条件。 让我提醒您,前置条件检查程序的状态(输入参数,对象状态,使用的变量)是否符合已执行代码段的必要要求。 后置条件(它们在程序中较不常见)旨在验证我们是否已达到所需的结果,并且对象的状态对于当前代码片段仍然有效。
建议的宏的使用非常简单-我们将每个检查分配到一个单独的宏中。 我们根据需要的错误处理选择宏。 (VERIFY_EXIT()-从该函数退出的错误处理,VERIFY_RETURN()-返回值的错误处理,VERRIFY_THROW()-带有异常的错误处理,等等。)
您还可以添加或使用VERIFY()宏,该宏不会执行任何错误处理。 这可能很有用,例如在函数结束时的后期条件中。
如果您使用纯代码原理并分配足够的功能来实现原子动作,则这些宏将完全自给自足。 每个函数都可以检查对象的状态,输入参数等。 进行原子动作。
2)交易的语义。
同样,这些宏可用于实现具有事务语义的代码。 这种语义可以理解为:1)逐步验证操作的每个准备阶段的结果; 2)只有在所有准备阶段都成功的情况下,才执行该动作; 3)如果在准备阶段未满足某些条件(可能会因履行而回退),则拒绝履行。
3)设计代码,并考虑可能的扩展。
对于库和通用代码而言尤其如此,它们最初可以在单个执行条件的上下文中进行开发,然后可以开始与其他条件一起使用(开始以不同的方式使用)。 在这种情况下,这些宏可以描述代码功能的“边界”。 确定最初被视为错误的内容以及成功的内容。 (这种方法接近经典的发布前条件。)当然,我将“边界”用引号引起来,因为 这些边界可以修改,但是重要的是确定(或传递给将来的开发人员)有关代码设计可接受边界的知识。
宏实施
我假设大多数中级开发人员在实现这些宏时都不会遇到问题。 但是,如果您需要信息,那么我将提供一些重点。
宏必须可表示为单个语句。 do {} while(false)构造或类似构造可以做什么。 例如,像这样:
#define VERFY_EXIT(cond) \ do{bool _= (bool)(cond); assert(_); if(!_) {return;}} while(false) \
然后,您可以编写以下代码:
if(a > 0) VERIFY_EXIT(a%2==0);
当然,这仅仅是实现可能性之一。 您可以通过其他方式实现宏。
PS与熵成功战斗,超人!