Pull to refresh

Comments 16

Выскажу свое мнение:
макрос VERIFY_RETURN сильно нарушает принцип «вызов макроса должен быть максимально приближен к вызову обычной функции». Очень сильно снижает понимание кода на мой взгляд. Опять же, переводить потом такой код на C++20 contracts будет тяжело.
Большое спасибо. Отличное замечание.

Тоже использую в процессе разработки похожие "маленькие хитрости" вместо обычного assert.
Когда хотелось бы сообщить, что "у нас тут что-то пошло не совсем так, как задумано", или "в этом месте надо получше проверить", но при этом, чтобы "без паники, ничего страшного пока не случилось".


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


Вторая просто издает встроенным динамиком характерный короткий звук.


Спасибо за статью.

Вместе функции с брякой на винде можно использвать DebugBreak/__debugbreak, а в линуксе raise(SIGTRAP).
DebugBreak — это хорошая штука. Но бывает, что вдруг этот «бряк» потребовалось временно отменить (типа, «да я уже все понял, пожалуйста, перестань мне бряки сыпать и дай транзакцию завершить нормально)
В IDE точка останова BreakPoint включается и выключается при необходимости одним щелчком мыша. Плюс всякие бонусы типа счетчиков и доп. действий (»останови здесь, но не при первом проходе, а на 1587-й раз", или «не надо тут останавливаться, но в журнал запиши»)

А для отмены или изменения DebugBreak придется код на лету менять. Не всегда это удобно.

Еще есть вариант
asm __volatile("int3");
Который, насколтко я помню, работает в GCC и на винде и на линуксе.

Автор, вы неверно понимаете назначение ассертов.
Классические труды по C++ говорят, что:
  • ассерты для отладки. Т.е. если сработал ассерт, надо исправлять код.
  • исключения для исключительных ситуаций, т.е. задача не может быть выполнена, но продолжение работы возможно где-то в другом месте
  • обработка ошибок для нормальной работы, т.е. для обработки тех ошибок, которые встречаются в обычной работе с программой, например: пользовательский ввод


Именно поэтому обычный макрос assert в релизе превращается в тыкву :)
В статье отмечено, что данное предложение:
1) для проектов без «идеальной» обработки ошибок;
2) для проектов, которые не могут по тем или иным причинам проводить достаточное тестирование перед выпуском в релиз, чтобы определить все срабатывания assert()-ов на этапе тестирования.

Согласен с вашими пунктами 1, 2 и 3. Но мы, к сожалению, не в идеальном мире живем. Предложено весьма и весьма компромиссное решение. В духе — лучше мало, чем совсем ничего. И, конечно, да «любите Бродского, почитайте наконец-то и других поэтов» — задумайтесь о нормальной системе обработки ошибок.
Разработчики контрактов в новом стандарте как раз таки вдохновлялись идеей, что мы не в идеальном мире живем) Там возможность превратить срабатывания ассерта — в исключение — изначально задумана.
Именно поэтому обычный макрос assert в релизе превращается в тыкву :)

И более того при зрелом процессе assert-ы должны быть убраны из кода (хотя ловушки на фатальные ошибки могут продолжать иметь место быть, но это другая история)

В glib/gobject для такого есть g_return_if_fail (cond, returnable), так что технология не нова.


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

В UE4 и PhysX тоже пачка таких макросов
UFO just landed and posted this here
UFO just landed and posted this here
да, лучше вариант, например:

#define VERFY_EXIT(cond)	\
do{bool _= false; assert(_ = (bool)(cond)); if(!_) {return;}} while(false)	\
/*end macro VERIFY_EXIT()*/
Sign up to leave a comment.

Articles