#c #assert
#c #утверждать
Вопрос:
У меня есть практика использования c assert для проверки, работает ли программа нормально, например, так:
cv::Mat im = imread("pic.jpg")
assert(!im);
Это проверит, правильно ли прочитано изображение. Это полезно, поскольку изображение может быть неправильно размещено в ожидаемом каталоге, поэтому нам нужно проверить. Я чувствую, что использование assert
удобно, но люди говорят, что использование assert
приведет к накладным расходам на программу, и предлагается их не использовать. Почему assert
приведет к накладным расходам? Что рекомендуется проверять в этом случае?
Комментарии:
1.
assert()
будет делать что угодно только в том случае,-DNDEBUG
если не задано. Это функция отладки , в основномif ( ! (!im) ) { abort() }
завернутая в#ifndef NDEBUG
. Кто сказал, что это «приведет к накладным расходам»?2. Просто для ясности, вы говорите о std::assert, правильно? en.cppreference.com/w/cpp/error/assert
3. Ваше использование
assert
проблематично. Я предполагаю, что это «работает» для вас, потому что вы не создаете конфигурации выпуска. Как толькоNDEBUG
установлено, утверждение в основном не существует в вашей программе. Это означает, что неудачное чтение не будет проверяться, и ваша программа попытается использовать недопустимый образ. Такого рода проверка не относится к утверждению.4. Кстати,
std:asert
сбой, если условие равно FALSE. Итак, в вашем случае произойдет сбой, еслиcv::Mat
правильно загружено.5. Нет
std::assert
; в#include <cassert>
заголовке естьassert
макрос. Макросы не являются частью пространства имен.
Ответ №1:
Во-первых, assert()
это не обычная функция. Это макрос, который выглядит примерно так:
#ifdef NDEBUG
#define assert(condition) ((void)0)
#else
#define assert(condition) /*implementation*/
#endif
и, как вы видите, он включен и делает что-то только тогда, NDEBUG
когда это не определено. Он предназначен для выполнения дополнительных проверок вашей программы при запуске в режиме отладки, чтобы помочь быстрее выявлять ошибки (например, неправильные аргументы, неверные инварианты и т.д.).
Assert сам по себе, вероятно, не требует такой высокой производительности, если вы используете его так, как вы показали, но из-за того, что я написал выше — это инструмент отладки — может использоваться во многих местах кодовой базы. Если условия, переданные в assert, сложны, конечно, для их оценки может потребоваться время (и вашим клиентам не нужно беспокоиться, потому что это произойдет только в режиме отладки, поэтому они не будут затронуты — NDEBUG
все эти накладные расходы исчезнут).
Вам не следует использовать assert()
для проверки то, что вы хотите всегда проверять (также в режиме без отладки). В этом случае правильно делать:
cv::Mat im = imread("pic.jpg")
if (!im) {
/* handle error ... */
}
Комментарии:
1. Будет ли std::assert приводить к накладным расходам на программу или точно так же, как
if(....) {abort();}
?2. @CoinCheung В сборках релизов это выглядит так, как если
assert
бы он был вручную удален из кода перед компиляцией.3. @CoinCheung Я чувствую, что вы пропустили ту часть этого ответа, которая объясняет
assert
, что здесь не подходит.assert
никогда не следует использовать для проверки чего-либо, что может привести к сбою. Ее следует использовать только для проверки того, что то, что вы уже знаете, всегдаtrue
есть на самом делеtrue
.4. @CoinCheung — нет
std::assert
, простоassert
. Как говорится в этом ответе, это макрос. На макросы не влияют области или пространства имен.5. @CoinCheung Это был бы возможный способ сделать это.
Ответ №2:
Почему функция c assert() приводит к накладным расходам на программу
Во-первых, assert
технически это не функция. Это макрос.
Чтобы ответить на вопрос: это зависит. Если утверждения отключены, то проверки не будет и, следовательно, никаких накладных расходов. Если утверждения включены, то да, будут накладные расходы по сравнению с отсутствием проверки (если только компилятор не сможет доказать во время компиляции, что проверка не нужна).
Ответ №3:
Любой дополнительный код добавит «накладные расходы» программе, например, при добавлении времени выполнения, размера кода, возможно, размера оперативной памяти.
То же самое верно для кода, который использует assert()
(за исключением деталей, которые assert()
выполняют свою работу и используют любые ресурсы только в том случае, если они активны, т. Е. Если -DNDEBUG
они не используются; за эту деталь благодарит DevSolar).
Оба вида кода, с и без assert()
, тем не менее, добавляются в программы, потому что, конечно, они служат определенной цели.
Вы четко и адекватно описали цель использования assert()
.
Теперь вопрос не в том, использует ли она какие-либо ресурсы, а в том, хотите ли вы достичь цели, за которую вы, вероятно, готовы заплатить цену использованных ресурсов.
Поскольку вы, кажется, совершенно уверены в преимуществах, это кажется адекватным решением для использования assert()
.
В случае, если вы запрашиваете какие-либо альтернативы использованию assert()
, ответ заключается в том, что нет ни одного, который поддерживал бы ту же цель без использования каких-либо ресурсов.
Вы также можете подумать, что в тех случаях, когда вам больше не нужны функции самопроверки (на мой взгляд, это обычно никогда не бывает), и действительно сосредоточиться на «без накладных расходов», тогда вы можете использовать упомянутый переключатель для удаления потребления ресурсов.