【问题标题】:Testing against the C++20 contracts (assertions)针对 C++20 合约进行测试(断言)
【发布时间】:2019-05-03 06:56:02
【问题描述】:

Herb Sutter 就 C++ 中异常的未来以及即将替换或增强现有 assert 的合同提交了 talk at ACUU Conference

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

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

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

  3. 可恢复的错误(例如,网络故障):异常,错误代码

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

来自documentation(重点是我的):

可以使用两种违规继续模式之一来翻译程序:

  • off(如果没有选择继续模式则默认):执行后 违规处理程序完成后,调用 std::terminate;
  • on:违规处理程序执行完成后,执行 继续正常进行。

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

这意味着将针对合约进行测试的测试程序将需要额外的编译开关。虽然我不喜欢这样,但我理解为什么会这样。更令人担忧的是最后一部分,以及关于它的问题has been raised。如果设置我们自己的合同违规处理程序的能力是实现定义的,那么它在工具链之间将不一致。因此,如果可能的话,对合约的任何测试都不会是可移植的。将它设置为链接器的另一个参数也会很尴尬(而且绝对不可移植)。

目前,无法针对assert 进行测试,因为它只是中止程序,而据我所知,自定义处理程序无法阻止这种情况。对于合约,这应该可以使用自定义处理程序和构建开关来实现,但事实证明,它可能也不可能(或由实现定义)。

或者是否有任何其他方法可以针对断言和合同进行测试,但我可能会遗漏?

【问题讨论】:

  • "目前无法针对 assert 进行测试,因为它只是中止程序,而据我所知,自定义处理程序无法阻止。" 在讨论合同时,他们是一般说的是合约[[assert:]],而不是宏assert
  • @NicolBolas 当然是的,但问题几乎相同。不同之处在于调用处理程序时将有一个关闭中止的选项。但是,如果不允许自定义处理程序,则无法检查它是否被调用(违反合同)。

标签: c++ contract c++20


【解决方案1】:

在违反合同方面没有太大的实施差异。 “build level”确定合同检查是否发生。违规处理程序将在任何检查失败的合同上被调用。

处理程序的原型由规范定义。关于违规处理程序的唯一实现差异是您如何设置它。请注意,“实现定义”并不意味着“不允许这种情况发生”。也就是说,the standard says that there will be a mechanism to establish the handler,并且该机制与实现一起记录(这就是“实现定义”的意思,而不仅仅是“未指定”)。该机制究竟是什么将取决于实现,但不提供这种机制不是选项。

唯一可能出现的真正问题是,如果多个实现决定允许用户通过指定特定全局名称来指定处理程序,并且这些实现是否使用不同的全局名称。然而,鉴于许多原因(与现有代码、宏等冲突)选择全局名称是一个坏主意,这在现实中不太可能成为问题。因此,他们很可能会选择显而易见的机制:编译器开关,指定用作处理程序的函数名称。

请注意,将处理程序定义为静态而不是运行时定义的原因之一是确保该开关是编译器 开关而不是链接器开关。毕竟,编译器是发出任何概念检查代码的那个。所以编译器可以在所说的检查代码中使用有问题的函数的名称。

当然,不同的编译器可能/将会有不同的编译器开关来确定调用哪个函数。但是他们已经有了不同的开关来生成调试信息、优化级别,基本上还有其他一切。因此,您使用的任何跨平台测试系统都需要能够处理此类区别。违规处理程序只是另外一个。

【讨论】:

    猜你喜欢
    • 2021-10-25
    • 2013-03-30
    • 2018-10-21
    • 2017-06-11
    • 2019-09-23
    • 1970-01-01
    • 2014-03-14
    • 1970-01-01
    • 2013-07-24
    相关资源
    最近更新 更多