В большинстве ответов предлагается использовать static_cast<void>(expression)
трюк в Release
сборках для подавления предупреждения, но это на самом деле неоптимально, если вы собираетесь делать проверки действительно Debug
только. Цели рассматриваемого макроса утверждения:
- Выполнять проверки в режиме
Debug
- Ничего не делать в режиме
Release
- Не выдавать предупреждения во всех случаях
Проблема заключается в том, что подход с использованием пустых ролей не достигает второй цели. Хотя предупреждения отсутствуют, выражение, которое вы передали в макрос утверждения, все равно будет оценено . Если вы, например, просто делаете проверку переменных, это, вероятно, не имеет большого значения. Но что, если вы вызовете некоторую функцию в проверке утверждений, например ASSERT(fetchSomeData() == data);
(что очень часто встречается в моем опыте)? Функция fetchSomeData()
будет по-прежнему вызываться. Это может быть быстро и просто или нет.
Что вам действительно нужно, так это не только подавление предупреждений, но, возможно, что еще более важно - не оценка контрольного выражения только для отладки. Это может быть достигнуто простым трюком, который я взял из специализированной библиотеки Assert :
void myAssertion(bool checkSuccessful)
{
if (!checkSuccessful)
{
// debug break, log or what not
}
}
#define DONT_EVALUATE(expression) \
{ \
true ? static_cast<void>(0) : static_cast<void>((expression)); \
}
#ifdef DEBUG
# define ASSERT(expression) myAssertion((expression))
#else
# define ASSERT(expression) DONT_EVALUATE((expression))
#endif // DEBUG
int main()
{
int a = 0;
ASSERT(a == 1);
ASSERT(performAHeavyVerification());
return 0;
}
Вся магия в макросе DONT_EVALUATE
. Очевидно, что по крайней мере логически оценка вашего выражения никогда не требуется внутри него. Чтобы усилить это, стандарт C ++ гарантирует, что будет оцениваться только одна из ветвей условного оператора. Вот цитата:
5.16 Условный оператор [expr.cond]
логическое или-выражение? выражение: присваивание-выражение
Группа условных выражений справа налево. Первое выражение
контекстно преобразуется в bool. Это оценивается, и если это правда,
Результатом условного выражения является значение второго
выражение, в противном случае это выражение третьего выражения. Только один из них
выражения оценивается.
Я тестировал этот подход в GCC 4.9.0, clang 3.8.0, VS2013 Update 4, VS2015 Update 4 с наиболее жесткими уровнями предупреждений. Во всех случаях нет предупреждений, и проверочное выражение никогда не оценивается в Release
сборке (фактически все полностью оптимизируется). Имейте в виду, однако, что при таком подходе вы очень быстро столкнетесь с трудностями, если поместите выражения, которые имеют побочные эффекты, в макрос утверждения, хотя это очень плохая практика.
Кроме того, я ожидаю, что статические анализаторы могут предупреждать о «результате выражения всегда постоянны» (или что-то в этом роде) при таком подходе. Я проверил это с помощью инструментов статического анализа clang, VS2013, VS2015 и не получил подобных предупреждений.