Являются ли утверждения всегда плохими?

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

Я считаю, что они чрезвычайно важны при написании правильного кода. Может ли кто-нибудь предложить, как такой мандат может быть оправдан? Если да, то что не так с утверждениями?

Ответ 1

Мы используем модифицированную версию assert в соответствии с комментарием JaredPar, который действует как контракт. Эта версия скомпилирована в код выпуска, поэтому накладные расходы небольшого размера, но отключены, если не установлен диагностический переключатель, так что служебные данные производительности минимизированы. Наш обработчик assert в этом случае может быть настроен на отключенный, бесшумный режим (например, журнал на файл) или шумный режим (например, отображение на экране с отменой/игнорированием, где abort вызывает исключение).

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

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

Ответ 2

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

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

  • Код подтверждения имеет заметное влияние.
  • Конкретное условие не является фатальным.
  • Иногда есть фрагмент кода, который может быть или не быть мертвым. Мы добавим утверждение, в котором говорится, "как вы сюда попали". Не стрельба не означает, что код действительно мертв, но если QA отправляет мне электронное письмо и говорит "что означает это утверждение", теперь у нас есть репродукция, чтобы перейти к определенному фрагменту кода (он сразу задокументирован, конечно).

Ответ 3

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

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

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

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

Ответ 4

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

Например, я не буду использовать утверждения в банковском приложении или в телекоммуникационной системе: я бы выбрал исключение, которое будет уловлено в стеке вызовов. Там можно очистить ресурсы, и следующий вызов/транзакция может быть обработана; только один будет потерян.

Ответ 5

Утверждения - отличная вещь, но ее нельзя путать с проверкой значения параметра/возвращаемого значения. Вы используете их в ситуациях, которые, как вы считаете, не произойдут, а не в ситуациях, которые вы ожидаете, могут произойти.

Мое любимое место для их использования - это блоки кода, которые действительно не должны быть достигнуты - например, default case в switch -statement над перечислением, которое имеет case для каждого возможного значения перечисления.

Относительно распространено, что вы можете расширять перечисление новыми значениями, но не обновляете все switch -статы, содержащие перечисление, вы захотите узнать это как можно скорее. Неудачное и быстрое - это лучшее, что вы можете пожелать в таких обстоятельствах.

Конечно, в тех местах вы обычно хотите что-то, что ломается в производственных сборках. Но настоятельно рекомендуется использовать принцип abort() при таких условиях. Хорошая трассировка стека в отладчике дает вам информацию, чтобы исправить вашу ошибку быстрее, чем гадать.

Ответ 6

Правда ли, что в сборке отладки существует утверждение, но не в сборке релизов?

Если вы хотите проверить/утверждать что-то, не хотите ли вы сделать это в сборке выпуска, а также в сборке отладки?

Ответ 7

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

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

Ответ 8

Мы используем утверждения для документирования допущений.

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

Ответ 9

Утверждения могут быть оставлены просто, не определяя NDEBUG, так что это не проблема.

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

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

Ответ 10

Одна из причин вето assert() заключается в том, что можно писать код, который работает корректно, когда NDEBUG определен, но сбой, если NDEBUG не определен. Или наоборот.

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

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

Ответ 11

Обратите внимание, что исключение в деструкторе - это поведение undefined.