我的大多数类都有调试变量,这使得它们经常看起来像这样:
class A { // stuff #ifndef NDEBUG int check = 0; #endif };
并且方法可能如下所示:
for (/* big loop */) { // code #ifndef NDEBUG check += x; #endif } assert(check == 100);
几乎没有什么比所有这些#ifndef NDEBUG的东西更糟糕.不幸的是没有编译器我知道可以优化检查变量没有这些#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; };
然后我可以使用检查,就像它是一个正常的变量!真棒!但是,还有两个问题我无法解决:
它只适用于int,float等
“null”类没有push_back()等.没有biggie.大多数调试变量都是int.
“空类”是1个字宽!
C中的每个类都至少为1个char.所以即使在释放模式下,使用N个调试变量的类将至少为N个字符太大.这在我眼里是不能接受的.这是我尽可能追求的零开销原则.
那么,如何解决这个第二个问题呢?在非调试模式下,甚至可以摆脱#ifndef NDEBUG而不伤害性能?我接受任何好的解决方案,即使它是你最黑暗的C魔法或C 0x.
解决方法
怎么样:
#ifndef NDEBUG #define DEBUG_VAR(T) static nullclass<T> #endif
现在,没有额外的存储被添加到使用DEBUG_VAR(T)作为成员的类,但声明的标识符仍然可以被使用,就像它是一个成员一样.