Я читал о контрактах в Мысли о C ++ 17 Б. Страуструпа и помогал в небольшой презентации, рассказывая о них, но я не уверен, что я действительно понял их.
Итак, у меня есть несколько опросов и, если возможно, проиллюстрировать их примерами:
Являются ли контракты просто лучшей заменой классического assert()
и должны ли они использоваться вместе? Какие контракты действительно заключаются в простых терминах для разработчика программного обеспечения?
Будут ли контракты влиять на то, как мы обрабатываем исключения? Если да, как мы должны использовать исключения и контракты?
Означает ли использование контрактов накладные расходы во время исполнения? Будем ли мы разрешать их деактивировать при выпуске кода?
Редактировать из предложение N4415 :
Контракт предварительного условия оператора индексирования класса Vector может быть записан:
T& operator[](size_t i) [[expects: i < size()]];
Точно так же контракт после условия для конструктора класса ArrayView может быть выражен как:
ArrayView(const vector<T>& v) [[ensures: data() == v.data()]];
Насколько я прочитал из этого документа:
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 документа, упомянутого в начале этого поста, рассказывает о возможностях отключения контрактов в зависимости от конфигурации вашей сборки, как это делают обычные старые утверждения.
Я начал с ссылка на сайт из оригинального документа OP.
Есть несколько ответов, я полагаю. Я настоятельно рекомендую начать с этой статьи. Вот тл&Версия DR:
Контракты не являются общим механизмом сообщения об ошибках и не являются
заменить тестирование фреймворков. Скорее, они предлагают основные
меры по смягчению, когда программа идет не так из-за
несоответствие ожиданий между частями программы.
Контракты концептуально больше похожи на структурированные
assert () интегрирован в язык, играет языком
правила семантики — поэтому основа для принципиального анализа программ
и оснастка.
О ваших вопросах:
…выражение контракта должно быть логически частью
декларация об операции.
и пример:
T& operator[](size_t i) [[expects: i < size()]];
На мой взгляд, это просто красиво и читабельно.
Однако критически важным критерием проектирования является возможность использования контрактов во встроенных системах или других системах с ограниченными ресурсами, которые не могут
позволить себе исключения.
В контрактах с предварительными условиями все еще могут использоваться исключения, поскольку дальнейшее поведение после отказа контракта с предварительными условиями не гарантируется.
Некоторые варианты использования (как я могу предположить, хотя я даже не близок к разработке дизайна контракта)
assert()
как контрактыПредварительное условие операции оценивается перед любым другим
утверждение в теле функции. Если результат верен, то нормально
контроль выполнения продолжается до первого утверждения в теле
функция. В противном случае дальнейшее выполнение не гарантируется: либо
программа прерывает или выдает исключение, или если это разрешено
продолжить, тогда поведение не определено.
Это также немного Другой предложения по выполнению контрактов, поэтому наше расследование просто преждевременно.
Нелегко ответить на ваши вопросы, кроме как: Это зависит. Это потому, что еще не ясно, какие контракты будут точно. Есть несколько предложений и идей, плавающих прямо сейчас:
N3737 Lakos et al. в основном предлагает стандартизировать сложный инструментарий assert. Контракты проверяются внутри реализации функций, для контроля количества проверок во время выполнения предоставляются 3 различных уровня утверждений, а также может быть настроена обработка нарушений утверждений.
N 4415 DOS ReIS et al. а также n4435 коричневый довольно похожи и предлагают основанный на атрибутах синтаксис для определения предварительных и последующих условий в интерфейсах функций. Они не вдавались в подробности о том, какой контроль они дают над проверками во время выполнения и поведением нарушений.
По этой теме тоже было меньше недавних работ. Есть много деталей, которые еще не определены, и эта особенность затрагивает множество различных областей (например, модули, оптимизация, сборка / связывание), над некоторыми из которых у стандарта мало контроля.
Ваш вопрос об исключениях особенно труден, потому что взаимодействие между обработкой нарушения контракта и исключениями неясно (например, может ли обработчик нарушения контракта бросить (полезно в тестовых средах) — что если функция noexcept(true)
?).