pyr*_*chi 12 c++ debugging iostream
我已经实现了一个ostream
for debug输出,它最终发送调试信息OutputDebugString
.它的典型用法看起来像这样(debug
ostream对象在哪里):
debug << "some error\n";
Run Code Online (Sandbox Code Playgroud)
对于发布版本,不输出这些调试语句的最不痛苦和最高效的方法是什么?
小智 9
最常见(当然也是性能最佳)的方法是使用预处理器删除它们,使用类似这样的东西(最简单的实现):
#ifdef RELEASE
#define DBOUT( x )
#else
#define DBOUT( x ) x
#endif
Run Code Online (Sandbox Code Playgroud)
然后你可以说
DBOUT( debug << "some error\n" );
Run Code Online (Sandbox Code Playgroud)
编辑: 您当然可以使DBOUT更复杂:
#define DBOUT( x ) \
debug << x << "\n"
Run Code Online (Sandbox Code Playgroud)
这允许更好的语法:
DBOUT( "Value is " << 42 );
Run Code Online (Sandbox Code Playgroud)
第二种方法是将DBOUT定义为流.这意味着您必须实现某种类型的null流类 - 请参阅实现no-op std :: ostream.但是,此类流在发布版本中确实具有运行时开销.
这个怎么样?您必须检查它在发布中实际上是否优化:
#ifdef NDEBUG
class DebugStream {};
template <typename T>
DebugStream &operator<<(DebugStream &s, T) { return s; }
#else
typedef ostream DebugStream;
#endif
Run Code Online (Sandbox Code Playgroud)
您必须将调试流对象作为DebugStream传递,而不是作为ostream传递,因为在发布版本中它不是一个.这是一个优点,因为如果您的调试流不是ostream,这意味着您不会产生支持ostream接口的空流的通常运行时惩罚(虚拟函数实际上被调用但什么都不做).
警告:我刚刚做了这个,通常我会做类似于Neil的回答 - 有一个宏意思"只在调试版本中执行此操作",因此它在源代码中显式是什么是调试代码,什么不是.我实际上并不想抽象的一些事情.
Neil的宏也有一个属性,绝对肯定不会在发布中评估它的论点.相比之下,即使我的模板内联,你会发现有时:
debug << someFunction() << "\n";
Run Code Online (Sandbox Code Playgroud)
不能被优化为什么,因为编译器不一定知道someFunction()
没有副作用.当然,如果someFunction()
确实有副作用,那么您可能希望在发布版本中调用它,但这是日志和功能代码的特殊混合.
更漂亮的方法:
#ifdef _DEBUG
#define DBOUT cout // or any other ostream
#else
#define DBOUT 0 && cout
#endif
DBOUT << "This is a debug build." << endl;
DBOUT << "Some result: " << doSomething() << endl;
Run Code Online (Sandbox Code Playgroud)
只要你不做任何奇怪的事情,调用和传递给的函数DBOUT
将不会在发布版本中调用.该宏因运算符优先级和逻辑AND而起作用; 因为&&
优先级低于<<
,发布版本编译DBOUT << "a"
为0 && (cout << "a")
.如果左侧的表达式求值为零,则逻辑AND不会评估右侧的表达式false
; 因为左手表达式总是计算为零,所以任何值得使用的编译器都会删除右手表达式,除非禁用所有优化(即使这样,显然仍然无法访问代码).
这是一个会破坏这个宏的奇怪事物的例子:
DBOUT << "This is a debug build." << endl, doSomething();
Run Code Online (Sandbox Code Playgroud)
看逗号.doSomething()
无论是否_DEBUG
定义,都将被调用.这是因为语句在发布版本中评估为:
(0 && (cout << "This is a debug build." << endl)), doSomething();
// evaluates further to:
false, doSomething();
Run Code Online (Sandbox Code Playgroud)
要在此宏中使用逗号,必须将逗号括在括号中,如下所示:
DBOUT << "Value of b: " << (a, b) << endl;
Run Code Online (Sandbox Code Playgroud)
另一个例子:
(DBOUT << "Hello, ") << "World" << endl; // Compiler error on release build
Run Code Online (Sandbox Code Playgroud)
在发布版本中,评估为:
(0 && (cout << "Hello, ")) << "World" << endl;
// evaluates further to:
false << "World" << endl;
Run Code Online (Sandbox Code Playgroud)
这会导致编译器错误,因为除非定义了自定义运算符,否则指针bool
不能向左移位char
.此语法还会导致其他问题:
(DBOUT << "Result: ") << doSomething() << endl;
// evaluates to:
false << doSomething() << endl;
Run Code Online (Sandbox Code Playgroud)
就像逗号使用得不好时一样,doSomething()
仍然会被调用,因为它的结果必须传递给左移运算符.(只有在定义了一个bool
通过char
指针左移的自定义运算符时才会发生这种情况;否则会发生编译错误.)
不要括号DBOUT << ...
.如果你想为一个字面整数移位括号,然后将它括起来,但我不知道有一个很好的理由来为一个流操作符括号.