В большинстве моих классов есть переменные отладки, поэтому они часто выглядят так:
class A
{
// stuff
#ifndef NDEBUG
int check = 0;
#endif
};
а методы могут выглядеть так:
for (/* big loop */) {
// code
#ifndef NDEBUG
check += x;
#endif
}
assert(check == 100);
Немногое уродливее, чем все эти #ifndef NDEBUG. К сожалению, ни один из известных мне компиляторов не может оптимизировать переменную check без этих #ifndefs (я не знаю, разрешено ли это вообще).
Итак, я попробовал чтобы найти решение, которое облегчило бы мою жизнь. Вот как это выглядит сейчас:
#ifndef NDEBUG
#define DEBUG_VAR(T) T
#else
template <typename T>
struct nullclass {
inline void operator+=(const T&) const {}
inline const nullclass<T>& operator+(const T&) const { return *this; }
// more no-op operators...
};
#define DEBUG_VAR(T) nullclass<T>
#endif
Итак, в режиме отладки DEBUG_VAR (T) просто создает T. В противном случае он создает «нулевой класс» только без операций. И мой код будет выглядеть так:
class A {
// stuff
DEBUG_VAR(int) check;
};
Тогда я мог бы просто использовать check , как если бы это была обычная переменная! Отлично! Однако есть еще 2 проблемы, которые я не могу решить:
«Нулевой класс» не имеет push_back () и т. Д. Ничего особенного. В любом случае, большинство переменных отладки - это целые числа.
Каждый класс в C ++ имеет ширину не менее 1 символа. Таким образом, даже в режиме выпуска класс, который использует N отладочных переменных, будет по крайней мере на N символов больше. Это в моих глазах просто недопустимо. Это противоречит принципу нулевых накладных расходов, к которому я стремлюсь изо всех сил.
Итак, как мне решить эту вторую проблему? Можно ли вообще избавиться от #ifndef NDEBUG, не повредив производительность в режиме без отладки? Я принимаю любое хорошее решение, даже если это ваше самое мрачное волшебство на C ++ или C ++ 0x.