В чем разница между assert и static_assert?
Я знаю, что static_assert
делает утверждения во время компиляции, а assert
- во время выполнения, но в чем разница на практике? Насколько я понимаю, в глубине души это фрагменты кода, например
if (condition == false) exit();
- Может ли кто-нибудь дать мне пример того, где будет работать только
static_assert
, или только assert
?
- Делают ли они что-нибудь, что не может сделать простой оператор
if
?
- Используется ли им плохая практика?
Ответы
Ответ 1
Вы задаете три вопроса, поэтому я постараюсь ответить на каждый из них.
- Может ли кто-нибудь дать мне пример того, где будет работать только
static_assert
, или только assert
?
static_assert
хорош для тестирования логики в коде во время компиляции. assert
хорош для проверки дела во время выполнения, который, как вы ожидаете, всегда должен иметь один результат, но, возможно, каким-то образом может привести к неожиданному результату при непредвиденных обстоятельствах. Например, вы должны использовать только assert
для определения того, был ли указатель, переданный в метод, null
, когда кажется, что этого никогда не должно происходить. static_assert
не поймает этого.
- Делают ли они что-либо, что не может сделать простой оператор
if
?
assert
может использоваться для прерывания выполнения программы, поэтому вы можете использовать if
, соответствующее сообщение об ошибке, а затем прекратить выполнение программы, чтобы получить аналогичный эффект, но assert
в этом случае немного проще, static_assert
, конечно, применим только для обнаружения проблемы компиляции, тогда как if
должен быть программно действительным и не может оценивать одни и те же ожидания во время компиляции. (Однако if
можно использовать для высылки сообщения об ошибке во время выполнения.)
- Используется ли им плохая практика?
Совсем нет!
Ответ 2
static_assert
предназначен для сбоя компиляции с указанным сообщением, тогда как традиционный assert
предназначен для завершения выполнения вашей программы.
Ответ 3
ОК, я укушу:
-
Работает только static_assert
, если вы хотите, чтобы компиляция прекратилась неудачно, если статическое условие нарушено: static_assert(sizeof(void*) != 3, "Wrong machine word size");
* Только динамические утверждения могут захватывать динамические условия: assert(argc == 1);
-
Простые инструкции if
должны быть действительными и компилируемыми; статические утверждения вызывают сбои компиляции.
-
Нет.
*) Практическим примером может быть предотвращение злоупотребления шаблонами общих шаблонов, таких как int x; std::move<int&&>(x)
.
Ответ 4
Используется ли им плохая практика?
Если злоупотребление, да, особенно assert
.
Одно из злоупотреблений зависит от того, какие операторы assert
должны быть активными. Вы никогда не должны зависеть от assert
делать что-либо, потому что код может быть скомпилирован с помощью NDEBUG
, а затем assert
ничего не делает. Производственный код часто компилируется с помощью NDEBUG
, определенного для обеспечения исчезновения этих операторов assert
.
Если вы не пишете одноразовую программу, которая не будет проживать больше одного или двух дней, вы не должны использовать для проверки ввода пользователя. Пользователям все равно, где код не удался, а печатное сообщение выглядит как иностранный язык для многих пользователей. Он не сообщает пользователю, как исправить ошибку. Это также очень неумолимо, по дизайну. Сообщение, выпущенное в ответ на ошибку ввода пользователя, должно быть сообщением, которое сообщает пользователю, как исправить проблему. Лучшее действие после сообщения - предложить пользователю способ исправить ошибку. Если это невозможно сделать, и если единственным жизнеспособным ответом является завершение программы, программа должна прекратиться. По дизайну assert
не приводит к чистому отключению. Он вызывает abort()
, а не exit()
.
Одним из следствий abort()
на многих машинах является создание дампа ядра. Дамп ядра - отличное сообщение об ошибке для программиста. С дампом ядра программист может использовать отладчик, чтобы увидеть, что пошло не так в деталях. Недостатком abort()
является то, что вещи не очищаются. Abort "завершает программу без выполнения деструкторов для объектов с автоматическим или статическим хранением и без вызова функций, переданных в atexit()
."
Нижняя строка: хорошо (и хорошо) использовать assert
для проверки ошибок программирования, но только в непроизводственной настройке. Используйте что-то еще, чтобы протестировать ошибки пользователя.
Ответ 5
static_assert
- это директива компилятора. Он позволяет проверять информацию о типе во время компиляции. Это приведет к сбою компиляции и вызовет сообщение об ошибке, которое в большинстве IDE будет обнаружено и отображено в окне ошибки IDE.
static_assert(sizeof(int) == 4,"int should be 4 bytes");
assert
предназначен для выполнения, вы можете проверить значение переменной. Если утверждение не сработает, это приведет к срабатыванию. Это вызовет окно с сообщением об ошибке, которое будет отображаться во время выполнения в некоторых операционных системах (утверждать, что реализация зависит)
assert(("mypointer should never be null!", mypointer != nullptr));