针对C 20合同的测试(断言)

Testing against the C++20 contracts (assertions)

本文关键字:断言 测试 合同 针对      更新时间:2023-10-16

Herb Sutter在ACUU会议上发表了关于C 例外和即将取代或增强现有断言的未来的演讲。

他假设以下规则处理错误处理:

  1. 系统损坏(例如,堆栈溢出(:终止

  2. 编程错误(例如违反前提条件(:断言,合同

  3. 可恢复的错误(例如,网络向下(:异常,错误代码

虽然我同意,但我没有使用这种方法,而是将 2 3 组合到一个。我这样做是因为我不知道如何测试断言或即将到来的合同。两者都使用类似的机制,即它们的违规行为会导致该程序终止并致电可选处理程序。

来自文档(强调是我的(:

一个程序可以通过两种违规延续模式之一进行翻译:

  • off(默认如果未选择延续模式(:执行后在违规处理程序完成的情况下,std :: terminate被称为;
  • on:执行违规处理程序完成后,执行正常继续。

鼓励实现不提供任何查询,设置或修改构建级别或设置或修改违规处理程序。

这意味着将针对合同进行测试的测试程序需要额外的汇编开关。虽然我不喜欢这个,但我明白为什么会这样。最后一部分是更多令人担忧的问题,并且已经提出了有关它的问题。如果设定自己的合同违规处理程序的能力是实现定义的,则在工具链之间将不一致。因此,如果可能的话,对合同的任何测试都不可移植。将其设置为链接器的另一个参数也很尴尬(并且绝对不是便携式(。

当前,对assert进行测试是不可能的,因为它只是简单地中止了程序,并且据我所知,自定义处理程序无法阻止它。有了合同,应该使用自定义处理程序和构建开关,但事实证明,也可能不可能(或实现定义(。

我是否有其他方法对断言和合同进行测试?

在合同违规方面没有太大的实现差异。"构建级别"确定合同检查是否发生。违规处理程序将被召集任何失败的检查合同。

处理程序的原型由规范定义。关于违规处理程序的唯一实现差异是您如何设置它。请注意,"实现定义"并不意味着"不允许这种情况发生"。也就是说,标准说,将是建立处理程序的机制,并且该机制将通过实施记录(这就是"实施定义"的含义,而不是仅"未指定"(。该机制的确取决于实施,但不能提供一个机制是不是选项。

唯一可能出现的问题是,如果多个实现决定允许用户通过祝福特定的全局名称来指定处理程序,并且这些实现使用了其他全局名称。但是,鉴于选择全球名称是一个坏主意,原因是多种原因(与现有代码,宏等发生冲突(,这在现实中不太可能是一个问题。因此,他们更有可能选择明显的机制:指定用作处理程序的功能名称的编译器开关。

请注意,使处理程序静态而不是运行时定义的定义的原因之一是确保开关是 compiler 开关而不是链接器开关。毕竟,编译器是发出任何概念检查代码的编译器。因此,编译器可以在上述检查代码中使用所讨论的函数的名称。

哦,可以肯定的是,不同的编译器可能会/将具有不同的编译器开关,以确定调用哪些函数。但是他们已经有不同的开关来生成调试信息,优化级别以及其他所有内容。因此,您使用的任何跨平台测试系统都将需要能够处理此类区别。违规处理程序只是另一个。