На comp.lang.c ++. Обсуждается вопрос о том, следует ли сохранять в рабочем коде утверждения, которые по умолчанию в C ++ существуют только в отладочных сборках.
Очевидно, что каждый проект уникален, поэтому мой вопрос здесь не столько ли следует хранить утверждения, а в каких случаях это рекомендуется / не является хорошей идеей.
Под утверждением я имею в виду:
- Проверка во время выполнения, которая проверяет условие, которое, если оно ложно, выявляет ошибку в программном обеспечении.
- Механизм, с помощью которого программа останавливается (возможно, после действительно минимальной работы по очистке).
Я не обязательно говорю о C или C ++.
Мое собственное мнение таково: если вы программист, но не владеете данными (что имеет место в большинстве коммерческих настольных приложений), вы должны оставить их включенными, потому что ошибочное утверждение показывает ошибку, и вы не должны идти с ошибкой, с риском повреждения данных пользователя. Это вынуждает вас тщательно тестировать перед отправкой и делает ошибки более заметными, что облегчает их обнаружение и исправление.
Каково ваше мнение / опыт?
Ура,
деревенщина
Смотрите связанный вопрос здесь
Отзывы и обновления
Привет, Грэм,
Утверждение является ошибкой, чистым и простым и поэтому должно обрабатываться как единое целое. Так как ошибка должна быть обработана в режиме релиза, тогда вам не нужны утверждения.
Вот почему я предпочитаю слово «ошибка», когда говорю об утверждениях. Это делает вещи намного понятнее. Для меня слово «ошибка» слишком расплывчато. Отсутствующий файл - это ошибка, а не ошибка, и программа должна с ней справиться. Попытка разыменования нулевого указателя является ошибкой, и программа должна признать, что что-то пахнет плохим сыром.
Следовательно, вы должны проверить указатель с утверждением, но наличие файла с нормальным кодом обработки ошибок.
Немного не по теме, но важный момент в обсуждении.
В качестве предупреждения, если ваши утверждения ломаются в отладчике, когда они терпят неудачу, почему бы и нет. Но существует множество причин, по которым файл не может существовать, которые полностью находятся вне контроля вашего кода: права на чтение / запись, заполнение диска, отключение USB-устройства и т. Д. Поскольку вы не можете контролировать его, я считаю, что утверждения не правильный способ справиться с этим.
деревенщина
Томас,
Да, у меня есть Code Complete, и я должен сказать, что я категорически не согласен с этим конкретным советом.
Скажем, ваш пользовательский распределитель памяти испортил и обнулил кусок памяти, который все еще используется другим объектом. Я получаю нулевой указатель, который регулярно разыменовывается в этом объекте, и один из инвариантов в том, что этот указатель никогда не равен нулю, и у вас есть пара утверждений, чтобы убедиться, что он остается таким. Что вы делаете, если указатель внезапно становится нулевым. Вы просто если () вокруг этого, надеясь, что это работает?
Помните, что мы говорим здесь о коде продукта, так что нет никакого взлома отладчика и проверки локального состояния. Это настоящая ошибка на компьютере пользователя.
деревенщина
Ответы:
Утверждения - это комментарии, которые не устаревают. Они документируют, какие теоретические состояния предназначены, а какие не должны возникать. Если код изменяется, и состояния разрешаются, разработчик вскоре получает уведомление и должен обновить утверждение.
источник
Позвольте мне процитировать полный код Стива Макконнелла. Раздел «Утверждения» - 8.2.
Однако позже в этом же разделе дается этот совет:
Я думаю, что пока производительность не является проблемой, оставьте утверждение, но вместо того, чтобы отображать сообщение, пусть оно записывает в файл журнала. Я думаю, что этот совет также есть в Code Complete, но сейчас я его не нахожу.
источник
Оставьте утверждения включенными в производственном коде, если только вы не измерили, что программа работает значительно быстрее при их отключении.
http://c2.com/cgi/wiki?ShipWithAssertionsOn
источник
assert ref != null;
отличается от того, чтоif (ref == null) throw new IllegalArgumentException();
вы не должны использовать первое для предварительных условий, которые могут быть ложными. Вы должны использоватьassert
для вещей, которые не могут быть ложными. Например,int i = -1 * someNumber; i = i * i;
потом напомнить людям, чтоi
это позитивно,assert i > 0;
Если вы даже хотите оставить утверждения в работе, вы, вероятно, думаете о них неправильно. Весь смысл утверждений заключается в том, что вы можете отключить их на производстве, поскольку они не являются частью вашего решения. Это инструмент разработки, используемый для проверки правильности ваших предположений. Но когда вы идете в производство, вы уже должны быть уверены в своих предположениях.
Тем не менее, есть один случай, когда я включу утверждения в рабочей среде: если мы сталкиваемся с воспроизводимой ошибкой в рабочей среде, которую нам трудно воспроизвести в тестовой среде, может быть полезно воспроизвести ошибку с включенными утверждениями в производстве, чтобы увидеть, если они предоставляют полезную информацию.
Более интересный вопрос заключается в следующем: когда вы отключаете утверждения на этапе тестирования?
источник
Утверждения никогда не должны оставаться в рабочем коде. Если конкретное утверждение кажется полезным в производственном коде, оно не должно быть утверждением; это должно быть время выполнения проверки ошибок, то есть что - то кодируется следующим образом:
if( condition != expected ) throw exception
.Термин «утверждение» стал означать «проверку только на время разработки, которая не будет проводиться на месте».
Если вы начнете думать, что утверждения могут дойти до поля, то вы неизбежно также начнете высказывать и другие опасные мысли, например, задаваться вопросом, действительно ли какое-либо данное утверждение действительно стоит делать. Нет утверждения, которое не стоит делать. Вы никогда не должны спрашивать себя: «Должен ли я утверждать это или нет?» Вы должны только спросить себя "Есть ли что-то, что я забыл утверждать?"
источник
Если профилирование не показывает, что утверждения вызывают проблемы с производительностью, я говорю, что они также должны оставаться в рабочей версии.
Тем не менее, я думаю, что это также требует, чтобы вы обрабатывали ошибки утверждений несколько изящно. Например, они должны приводить к общему типу диалога с возможностью (автоматически) сообщать о проблеме разработчикам, а не просто завершать или завершать работу программы. Кроме того, вы должны быть осторожны, чтобы не использовать утверждения для условий, которые вы действительно разрешаете, но, возможно, не любите или считаете нежелательными. Эти условия должны обрабатываться другими частями кода.
источник
В моем C ++ я определяю REQUIRE (x), который похож на assert (x), за исключением того, что он выдает исключение, если утверждение не выполняется в сборке выпуска.
Поскольку ошибочное утверждение указывает на ошибку, к ней следует относиться серьезно даже в сборке выпуска. Когда производительность моего кода имеет значение, я часто буду использовать REQUIRE () для кода более высокого уровня и assert () для кода более низкого уровня, который должен выполняться быстро. Я также использую REQUIRE вместо assert, если условие сбоя может быть вызвано данными, переданными из кода, написанного третьей стороной, или повреждением файла (оптимально я бы разработал код специально, чтобы он хорошо себя вел в случае повреждения файла, но мы не всегда есть время, чтобы сделать это.)
Они говорят, что вы не должны показывать эти сообщения об утверждении конечным пользователям, потому что они их не поймут. Так? Конечные пользователи могут отправить вам электронное письмо со снимком экрана или текстом сообщения об ошибке, которое поможет вам в отладке. Если пользователь просто говорит «он разбился», у вас меньше возможностей это исправить. Было бы лучше автоматически отправлять сообщения об ошибках подтверждения через Интернет, но это работает только в том случае, если у пользователя есть доступ в Интернет, и вы можете получить его разрешение.
источник
Если вы хотите сохранить их, замените их обработкой ошибок. Нет ничего хуже, чем просто исчезающая программа. Я не вижу ничего плохого в том, чтобы относиться к определенным ошибкам как к серьезным ошибкам, но они должны быть направлены в раздел вашей программы, который имеет возможность обрабатывать их, собирая данные, регистрируя их и информируя пользователя о том, что ваше приложение имело некоторые нежелательные условия и выходит
источник
При условии, что они обрабатываются так же, как и любая другая ошибка, я не вижу проблем с этим. Имейте в виду, что неудачные утверждения в C, как и в других языках, просто выйдут из программы, и этого обычно недостаточно для производственных систем.
Есть некоторые исключения - PHP, например, позволяет вам создать собственный обработчик ошибок подтверждения, чтобы вы могли отображать пользовательские ошибки, вести детальную регистрацию и т. Д. Вместо простого выхода.
источник
Наше программное обеспечение сервера баз данных содержит как производственные, так и отладочные утверждения. Отладочные утверждения - только это - они удалены в производственном коде. Производственные утверждения возникают только в том случае, если (а) существует какое-то условие, которое никогда не должно существовать, и (б) невозможно надежно восстановиться после этого условия. Производственное утверждение указывает, что в программном обеспечении обнаружена ошибка или произошло какое-либо повреждение данных.
Поскольку это система баз данных, и мы храним потенциально важные для предприятия данные, мы делаем все возможное, чтобы избежать повреждения данных. Если существует условие, которое может заставить нас хранить неверные данные, мы немедленно утверждаем, откатываем все транзакции и останавливаем сервер.
Сказав это, мы также стараемся избегать производственных утверждений в подпрограммах, критичных к производительности.
источник
Я вижу утверждения как встроенные юнит-тесты. Полезно для быстрого тестирования при разработке, но, в конечном счете, эти утверждения должны быть реорганизованы для внешнего тестирования в модульных тестах.
источник
Я считаю, что лучше всего обрабатывать все ошибки, которые находятся в области видимости, и использовать утверждения для предположений, которые, как мы утверждаем, истинны.
то есть, если ваша программа открывает / читает / закрывает файл, то невозможность открыть файл находится в области видимости - это реальная возможность, которую другими словами было бы небрежно игнорировать. Итак, с этим должен быть связан код проверки ошибок.
Однако предположим, что ваш fopen () задокументирован как всегда возвращающий действительный дескриптор открытого файла. Вы открываете файл и передаете его в функцию readfile ().
Эта функция readfile, в этом контексте и, вероятно, согласно своей спецификации проекта, может в значительной степени предполагать, что она получит правильный файл ptr. Таким образом, было бы расточительно добавлять код обработки ошибок для отрицательного случая в такой простой программе. Тем не менее, он должен по крайней мере документировать предположение, каким-то образом - каким-то образом гарантировать - что это действительно так, прежде чем продолжить его выполнение. Он не должен на самом деле предполагать, что он всегда будет действительным, если он вызывается неправильно или, например, копируется / вставляется в какую-то другую программу.
Итак, readfile () {assert (fptr! = NULL); ..} уместно в этом случае, тогда как полноценная обработка ошибок - нет (игнорируя тот факт, что для чтения файла в любом случае потребуется некоторая система обработки ошибок).
И да, эти утверждения должны оставаться в рабочем коде, если только это не является абсолютно необходимым для их отключения. Даже тогда вам, вероятно, следует отключить их только в разделах, критичных к производительности.
источник
Предположим, что часть кода находится в производстве, и он попадает в утверждение, которое обычно срабатывает. Утверждение нашло ошибку! За исключением того, что это не так, потому что утверждение отключено.
Так что теперь происходит? Либо программа будет (1) аварийно завершать работу в точке, удаленной от источника проблемы, либо (2) весело работать до конца, что, вероятно, даст неправильный результат.
Ни один сценарий не является привлекательным. Оставьте утверждения активными даже в производстве.
источник
Я редко использую утверждения для чего-либо другого, что проверяет тип времени компиляции. Я бы использовал исключение вместо утверждения только потому, что большинство языков созданы для их обработки.
Я предлагаю пример
против
Как приложение обработает утверждение? Я предпочитаю старый
try catch
метод борьбы с фатальными ошибками.источник
Большую часть времени, когда я использую утверждение в Java (ключевое слово assert), я автоматически добавляю некоторые производственные коды после. В зависимости от ситуации это может быть сообщение регистрации, исключение ... или ничего.
По моему мнению, все ваши утверждения имеют решающее значение в выпуске dev, а не в выпуске. Некоторые из них должны быть сохранены, другие должны быть отброшены.
источник
ПОЛОЖЕНИЯ не являются ошибками и не должны рассматриваться как ошибки. Когда выдается утверждение, это означает, что в вашем коде есть ошибка или, альтернативно, в коде, вызывающем ваш код.
Есть несколько моментов, по которым следует избегать включения утверждений в производственном коде: 1. Вы не хотите, чтобы ваш конечный пользователь видел сообщение типа «ASSERTION failed MyPrivateClass.cpp, строка 147. Конечный пользователь НЕ является инженером по обеспечению качества. 2. Возможно, ASSERTION влиять на производительность
Однако есть одна веская причина оставить утверждения: ASSERTION может влиять на производительность и время, и, к сожалению, это иногда имеет значение (особенно во встроенных системах).
Я склонен голосовать за то, чтобы оставить утверждение в производственном коде, но следя за тем, чтобы эти распечатки утверждений не были доступны конечному пользователю.
~ Ицик
источник
Утверждение является ошибкой, чистым и простым и поэтому должно обрабатываться как единое целое.
Так как ошибка должна быть обработана в режиме релиза, тогда вам не нужны утверждения.
Основным преимуществом утверждений, которые я вижу, является условный разрыв - их гораздо проще настроить, чем сверлить в окнах VC для настройки чего-то, что занимает 1 строку кода.
источник