Что такое контракты в C ++ 17

Я читал о контрактах в Мысли о C ++ 17 Б. Страуструпа и помогал в небольшой презентации, рассказывая о них, но я не уверен, что я действительно понял их.

Итак, у меня есть несколько опросов и, если возможно, проиллюстрировать их примерами:

  • Являются ли контракты просто лучшей заменой классического assert() и должны ли они использоваться вместе? Какие контракты действительно заключаются в простых терминах для разработчика программного обеспечения?

  • Будут ли контракты влиять на то, как мы обрабатываем исключения? Если да, как мы должны использовать исключения и контракты?

  • Означает ли использование контрактов накладные расходы во время исполнения? Будем ли мы разрешать их деактивировать при выпуске кода?

Редактировать из предложение N4415 :

Контракт предварительного условия оператора индексирования класса Vector может быть записан:
T& operator[](size_t i) [[expects: i < size()]];

Точно так же контракт после условия для конструктора класса ArrayView может быть выражен как:
ArrayView(const vector<T>& v) [[ensures: data() == v.data()]];

30

Решение

Насколько я прочитал из этого документа:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4415.pdf

Контракты делают то, что assert пытался сделать примитивным способом в течение многих лет. Они оба являются документацией и во время выполнения утверждают, как следует ожидать, что вызывающий вызов вызовет функцию, и в каком состоянии он может ожидать, что код будет после возврата функции. Они обычно известны как предварительные условия и постусловия или инварианты.

Это помогает очистить код на стороне реализации, потому что с контрактами мы можем предположить, что как только выполнение перешло в вашу функцию, ваши аргументы находятся в допустимом состоянии (что вы ожидаете от них).

Часть, связанная с постусловиями, может изменить способ обработки исключений, потому что с контрактами вам нужно будет убедиться, что создание исключения не нарушит ваши постусловия. Обычно это означает, что ваш код должен быть безопасным для исключений, хотя от ваших условий зависит, означает ли это строгую исключительную или базовую гарантию.

Пример:

Класс данных;
class MyVector {
общественности:
void MyVector :: push_back (Elem e) [[обеспечивает: данные! = nullptr]]
{
если (размер> = емкость)
{
Данные * р = данные;
data = nullptr; // Просто ради примера ...
данные = новые данные [емкость * 2]; // Может вызвать исключение
// Копируем p в данные и удаляем p
}
// Добавить элемент в конец
}
частный:
Данные * данные;
// другие данные
};

В этом примере здесь, если new или же Dataконструктор выдает исключение, ваше пост-условие нарушено. Это означает, что вы должны изменить весь такой код, чтобы ваш контракт никогда не нарушался!

Конечно, так же, как assertконтракты могут включать накладные расходы во время выполнения. Разница, однако, заключается в том, что, поскольку контракты могут быть помещены как часть объявления функции, компилятор может выполнять более эффективные оптимизации, такие как оценка условий на сайте вызывающей стороны или даже оценка их во время компиляции. Раздел 1.5 документа, упомянутого в начале этого поста, рассказывает о возможностях отключения контрактов в зависимости от конфигурации вашей сборки, как это делают обычные старые утверждения.

20

Другие решения

Я начал с ссылка на сайт из оригинального документа OP.
Есть несколько ответов, я полагаю. Я настоятельно рекомендую начать с этой статьи. Вот тл&Версия DR:

Контракты не являются общим механизмом сообщения об ошибках и не являются
заменить тестирование фреймворков. Скорее, они предлагают основные
меры по смягчению, когда программа идет не так из-за
несоответствие ожиданий между частями программы.
Контракты концептуально больше похожи на структурированные
assert () интегрирован в язык, играет языком
правила семантики — поэтому основа для принципиального анализа программ
и оснастка.

О ваших вопросах:

  • Это структурированная assert (), так что да, можно сказать, что в некоторых случаях assert () необходимо заменить на contract.
  • Позвольте мне использовать другую цитату здесь:

…выражение контракта должно быть логически частью
декларация об операции.

и пример:

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

На мой взгляд, это просто красиво и читабельно.

  • В некоторых случаях контракты могут заменить исключения:

Однако критически важным критерием проектирования является возможность использования контрактов во встроенных системах или других системах с ограниченными ресурсами, которые не могут
позволить себе исключения.

В контрактах с предварительными условиями все еще могут использоваться исключения, поскольку дальнейшее поведение после отказа контракта с предварительными условиями не гарантируется.

  • Накладные расходы могут быть уменьшены путем включения / выключения проверки контрактов в следующих случаях: использовать все, использовать не, только предварительное условие, только постусловие.
    Включенные контракты определенно добавят некоторые накладные расходы, как и любой тип проверок.

Некоторые варианты использования (как я могу предположить, хотя я даже не близок к разработке дизайна контракта)

  1. Контракты — в случае обычного assert() как контракты
    более читаемый и может быть оптимизирован во время компиляции.
  2. Утверждает — в модульных тестах, тестировании фреймворков и т. Д.
  3. Исключения — могут использоваться с предварительно оговоренными контрактами, как
    упоминается в статье:

Предварительное условие операции оценивается перед любым другим
утверждение в теле функции. Если результат верен, то нормально
контроль выполнения продолжается до первого утверждения в теле
функция. В противном случае дальнейшее выполнение не гарантируется: либо
программа прерывает или выдает исключение, или если это разрешено
продолжить, тогда поведение не определено.

Это также немного Другой предложения по выполнению контрактов, поэтому наше расследование просто преждевременно.

8

Нелегко ответить на ваши вопросы, кроме как: Это зависит. Это потому, что еще не ясно, какие контракты будут точно. Есть несколько предложений и идей, плавающих прямо сейчас:

  • N3737 Lakos et al. в основном предлагает стандартизировать сложный инструментарий assert. Контракты проверяются внутри реализации функций, для контроля количества проверок во время выполнения предоставляются 3 различных уровня утверждений, а также может быть настроена обработка нарушений утверждений.

  • N 4415 DOS ReIS et al. а также n4435 коричневый довольно похожи и предлагают основанный на атрибутах синтаксис для определения предварительных и последующих условий в интерфейсах функций. Они не вдавались в подробности о том, какой контроль они дают над проверками во время выполнения и поведением нарушений.

По этой теме тоже было меньше недавних работ. Есть много деталей, которые еще не определены, и эта особенность затрагивает множество различных областей (например, модули, оптимизация, сборка / связывание), над некоторыми из которых у стандарта мало контроля.

Ваш вопрос об исключениях особенно труден, потому что взаимодействие между обработкой нарушения контракта и исключениями неясно (например, может ли обработчик нарушения контракта бросить (полезно в тестовых средах) — что если функция noexcept(true)?).

3
По вопросам рекламы [email protected]