简体   繁体   English

什么是合同(针对 C++17 提出的建议)?

[英]What are contracts (as proposed for C++17)?

I read about contracts in Thoughts about C++17 by B. Stroustrup and assisted a small presentation talking about them but I am not sure I have understood them really.我在 B. Stroustrup 的《 Thoughts about C++17》中读到了契约,并协助了一个关于它们的小型演讲,但我不确定我是否真的理解它们。

So I have some interrogations and if it is possible to illustrate them with some examples :所以我有一些审问,如果可以用一些例子来说明它们:

  • Are contracts just a better replacement of the classic assert() , and should they be used together?合同只是经典assert()的更好替代品,它们是否应该一起使用? What contracts really are put in simple terms for a software dev?对于软件开发人员来说,哪些合同真的很简单?

  • Would contracts have an impact on how we handle exceptions?合同是否会影响我们处理异常的方式? If yes, how should we use exceptions and contracts?如果是,我们应该如何使用例外和合同?

  • Would using contracts imply an overhead at execution time?使用合约是否意味着执行时的开销? Will we be allowed to deactivate them on release code?我们会被允许在发布代码上停用它们吗?

From the proposal N4415 :来自提案 N4415

A pre-condition contract of the indexing operator of a Vector class could be written:可以编写 Vector 类的索引运算符的先决条件契约:
T& operator[](size_t i) [[expects: i < size()]];

Similarly, a post-condition contract on a constructor of an ArrayView class could be expressed as: ArrayView(const vector<T>& v) [[ensures: data() == v.data()]];类似地,ArrayView 类的构造函数上的后置条件契约可以表示为: ArrayView(const vector<T>& v) [[ensures: data() == v.data()]];

Thanks to @Keith Thompson comment:感谢@Keith Thompson 评论:

Contracts didn't make it into C++20 .合同没有进入 C++20 A new study group, SG21, has been created. 已经创建了一个新的研究组 SG21。

As far as I've read from this document: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4415.pdf据我从这份文件中读到: http : //www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4415.pdf

Contracts do what assert has been trying to do in a primitive way for years.合约做assert多年来一直试图以原始方式做的事情。 They're both documentation and a run-time assert of how the caller should be expected to call the function and in what state can the caller expect the code to be after the function has returned.它们既是文档,也是关于调用者应该如何调用函数以及在函数返回后调用者期望代码处于什么状态的运行时断言。 Those are usually known as pre-conditions and post-conditions, or invariants.这些通常被称为前置条件和后置条件,或不变量。

This helps clean up code on the implementation side, because with contracts we can assume that once the execution has gone inside your function, your arguments are in valid state (what you expect them to be).这有助于清理实现方面的代码,因为使用契约,我们可以假设一旦执行进入您的函数,您的参数处于有效状态(您期望它们是什么)。

The post-conditions part might change how you handle exceptions, because with contracts you will have to make sure that throwing an exception won't break your post-conditions.后置条件部分可能会改变您处理异常的方式,因为对于合同,您必须确保抛出异常不会破坏您的后置条件。 This usually means that your code has to be exception safe, though whether that means strong exception guarantee or basic guarantee depends on your conditions.这通常意味着您的代码必须是异常安全的,尽管这意味着强异常保证还是基本保证取决于您的条件。

Example:例子:

class Data;
class MyVector {
public:
    void MyVector::push_back(Elem e) [[ensures: data != nullptr]]
    {
        if(size >= capacity)
        {
            Data* p = data;
            data = nullptr; // Just for the sake of the example...
            data = new Data[capacity*2]; // Might throw an exception
            // Copy p into data and delete p
        }
        // Add the element to the end
    }
private:
     Data* data;
     // other data
};

In this example here, if new or Data 's constructor throws an exception, your post-condition is violated.在此示例中,如果newData的构造函数抛出异常,则违反了后置条件。 This means that you should change all such code to make sure your Contract is never violated!这意味着您应该更改所有此类代码以确保您的合同不会被违反!

Of course, just like assert , contracts might include a run-time overhead.当然,就像assert一样,合约可能包含运行时开销。 The difference though is that since contracts can be put as part of the function's declaration, the compiler can do better optimizations, such as evaluating the conditions at the caller's site or even evaluate them at compile time.但不同之处在于,由于合约可以作为函数声明的一部分,编译器可以进行更好的优化,例如在调用者站点评估条件,甚至在编译时评估它们。 Section 1.5 of the document mentioned at the beginning of this post talks about the possibilities of turning off contracts depending on your build configuration, just like plain old asserts.本文开头提到的文档的第 1.5 节讨论了根据您的构建配置关闭合约的可能性,就像普通的旧断言一样。

I started with the link from the original document OP provided.我从提供的原始文档 OP 中的链接开始。 There are some answers, I suppose.有一些答案,我想。 I strongly recommend to start with that paper.我强烈建议从那篇论文开始。 Here is TL&DR version:这是 TL&DR 版本:

Contracts are not a general error reporting mechanism, nor are they substitute for testing frameworks.合约不是通用的错误报告机制,也不是测试框架的替代品。 Rather, they offer a basic mitigation measure when a program goes wrong because of mismatch of expectations between parts of a program.相反,当由于程序各部分之间的期望不匹配而导致程序出错时,它们提供了基本的缓解措施。 Contracts are conceptually more like structured assert()integrated into the language, playing by the language semantics rules – therefore basis for principled program analysis and tooling.契约在概念上更像是集成到语言中的结构化 assert(),按照语言语义规则进行操作——因此是原则性程序分析和工具的基础。

About your questions:关于您的问题:

  • It's structured assert(), so yes, it can be said that in some cases assert() must be replace with contract.它是结构化的assert(),所以是的,可以说在某些情况下assert()必须替换为contract。
  • Let me use another quote here:让我在这里引用另一个引用:

...the expression of a contract must logically be part of the declaration of the operation. ...合约的表达在逻辑上必须是操作声明的一部分。

and example:和例子:

T& operator[](size_t i) [[expects: i < size()]];

In my opinion, this is just nice and readable.在我看来,这很好且可读。

  • In some cases contracts can replace exceptions:在某些情况下,合同可以代替例外:

However, it is a critical design criteria that contracts be usable in embedded systems or other resource-constrained systems that cannot afford exceptions.然而,合同可用于嵌入式系统或其他资源受限的系统,无法承受异常,这是一个关键的设计标准。

In pre-condition contracts exceptions still can be used, as further behavior after pre-condition contract failure is not guaranteed.在前置条件合约中,仍然可以使用异常,因为不能保证前置条件合约失败后的进一步行为。

  • Overhead can be reduced by turning contracts checking on/off in for cases: use all, use non, pre-condition only, post-condition only.可以通过在以下情况下打开/关闭合同检查来减少开销:全部使用、使用非、仅前置条件、仅后置条件。 Turned on contracts will definitely add some overhead, as any type of checks.开启合约肯定会增加一些开销,就像任何类型的检查一样。

Some use cases (as I can suppose while i am not even close to developing a contracts design)一些用例(我可以假设,虽然我什至还没有接近开发合同设计)

  1. Contracts - in case of usual assert() as contracts are more readable and can be optimized at compilation time.合同 - 在通常的assert()情况下,因为合同更具可读性并且可以在编译时进行优化。
  2. Asserts - in unit tests, testing frameworks etc.断言 - 在单元测试、测试框架等中。
  3. Exceptions - can be used with pre-conditioned contracts as mentioned in article:例外 - 可以与文章中提到的预处理合同一起使用:

The pre-condition of an operation is evaluated before any other statement in the function's body.在函数体中的任何其他语句之前评估操作的先决条件。 If the result is true, then normal control of execution continues to the first statement in the body of the function.如果结果为真,则执行的正常控制将继续到函数体中的第一条语句。 Otherwise, further execution is not guaranteed: either the program aborts, or throws an exception, or if it is allowed to continue then the behavior is undefined.否则,无法保证进一步执行:程序中止或抛出异常,或者如果允许继续执行,则行为未定义。

There are also some other suggestions about contracts implementation, so our investigation is just premature.还有一些关于合同实施的其他建议,所以我们的调查还为时过早。

It is not easy to answer your questions other that with: It depends.回答你的问题并不容易,除了:这取决于。 This is because it is not yet clear what contracts are going to be exactly.这是因为目前还不清楚具体的合同是什么。 There are several proposals and ideas floating around right now:现在有几个提议和想法在流传:

  • n4378 Lakos et al. n4378 拉科斯等人。 basically proposes to standardize a sophisticated assert toolkit.基本上建议标准化一个复杂的断言工具包。 Contracts are checked inside of a functions implementation, 3 different assert levels are provided to control the amount of runtime checks and the handling of assert violations can be customized.在函数实现内部检查契约,提供 3 个不同的断言级别来控制运行时检查的数量,并且可以自定义断言违规的处理。

  • n4415 dos Reis et al. n4415 dos Reis 等。 and n4435 Brown are fairly similar and propose a attribute based syntax to define pre and post conditions in the functions interfaces.n4435 Brown非常相似,并提出了一种基于属性的语法来定义函数接口中的前置和后置条件。 They do not go into details on how much control they give over run-time checks and the behavior on violations.他们没有详细说明他们对运行时检查和违规行为给予了多少控制。

There have been less recent papers on this topic, too.最近关于这个主题的论文也较少。 There are many details which are not yet decided, and this feature touches many different areas (eg modules, optimization, building/linking) over some of which the standard has little control.有许多细节尚未确定,此功能涉及许多不同的领域(例如模块、优化、构建/链接),其中一些标准几乎无法控制。

Your question on exceptions is particularly difficult, because the interactions between contract violation handling and exceptions is unclear (eg could a contract violation handler throw (useful in test frameworks)? what if the function is noexcept(true) ?).您关于异常的问题特别困难,因为合同违规处理和异常之间的交互尚不清楚(例如,合同违规处理程序是否会抛出(在测试框架中有用)?如果函数是noexcept(true)呢?)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM