Комментарии 16
макрос VERIFY_RETURN сильно нарушает принцип «вызов макроса должен быть максимально приближен к вызову обычной функции». Очень сильно снижает понимание кода на мой взгляд. Опять же, переводить потом такой код на C++20 contracts будет тяжело.
Тоже использую в процессе разработки похожие "маленькие хитрости" вместо обычного assert.
Когда хотелось бы сообщить, что "у нас тут что-то пошло не совсем так, как задумано", или "в этом месте надо получше проверить", но при этом, чтобы "без паники, ничего страшного пока не случилось".
Кроме макросов похожих на описанные в статье, для ловли своих багов иногда применяю еще макросы под кодовыми названиями "бряк" и "блям". Первая — это вызов статической функции, которая сама по себе ничего не делает, но в теле которой в отладчике постоянно установлен breakpoint.
Вторая просто издает встроенным динамиком характерный короткий звук.
Спасибо за статью.
В 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)
, так что технология не нова.
Для упрощения отладки можно задействовать макросы препроцессора для вывода строки и функции
Расширение макроса assert() для реализации минимальной обработки ошибок