Почему функция c assert() приводит к накладным расходам на программу

#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() , ответ заключается в том, что нет ни одного, который поддерживал бы ту же цель без использования каких-либо ресурсов.

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