I've implemented an ostream for debug output which sends ends up sending the debug info to OutputDebugString. A typical use of it looks like this (where debug is an ostream object):
debug << "some error\n";
For release builds, what's the least painful and most performant way to not output these debug statements?
The most common (and certainly most performant) way is to remove them using the preprocessor, using something like this (simplest possible implementation):
#ifdef RELEASE
#define DBOUT( x )
#else
#define DBOUT( x ) x
#endif
You can then say
DBOUT( debug << "some error\n" );
Edit: You can of course make DBOUT a bit more complex:
#define DBOUT( x ) \
debug << x << "\n"
which allows a somewhat nicer syntax:
DBOUT( "Value is " << 42 );
A second alternative is to define DBOUT to be the stream. This means that you must implement some sort of null stream class - see Implementing a no-op std::ostream. However, such a stream does have an runtime overhead in the release build.
A prettier method:
#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;
As long as you don't do anything weird, functions called and passed to DBOUT won't be called in release builds. This macro works because of operator precedence and the logical AND; because && has lower precedence than <<, release builds compile DBOUT << "a" as 0 && (cout << "a"). The logical AND doesn't evaluate the expression on the right if the expression on the left evaluates to zero or false; because the left-hand expression always evaluates to zero, the right-hand expression is always removed by any compiler worth using except when all optimization is disabled (and even then, obviously unreachable code may still be ignored.)
Here is an example of weird things that will break this macro:
DBOUT << "This is a debug build." << endl, doSomething();
Watch the commas. doSomething() will always be called, regardless of whether or not _DEBUG is defined. This is because the statement is evaluated in release builds as:
(0 && (cout << "This is a debug build." << endl)), doSomething();
// evaluates further to:
false, doSomething();
To use commas with this macro, the comma must be wrapped in parentheses, like so:
DBOUT << "Value of b: " << (a, b) << endl;
Another example:
(DBOUT << "Hello, ") << "World" << endl; // Compiler error on release build
In release builds, this is evaluated as:
(0 && (cout << "Hello, ")) << "World" << endl;
// evaluates further to:
false << "World" << endl;
which causes a compiler error because bool cannot be shifted left by a char pointer unless a custom operator is defined. This syntax also causes additional problems:
(DBOUT << "Result: ") << doSomething() << endl;
// evaluates to:
false << doSomething() << endl;
Just like when the comma was used poorly, doSomething() still gets called, because its result has to be passed to the left-shift operator. (This can only occur when a custom operator is defined that left-shifts a bool by a char pointer; otherwise, a compiler error occurs.)
Do not parenthesize DBOUT << .... If you want to parenthesize a literal integer shift, then parenthesize it, but I'm not aware of a single good reason to parenthesize a stream operator.
How about this? You'd have to check that it actually optimises to nothing in release:
#ifdef NDEBUG
class DebugStream {};
template <typename T>
DebugStream &operator<<(DebugStream &s, T) { return s; }
#else
typedef ostream DebugStream;
#endif
You will have to pass the debug stream object as a DebugStream&, not as an ostream&, since in release builds it isn't one. This is an advantage, since if your debug stream isn't an ostream, that means you don't incur the usual runtime penalty of a null stream that supports the ostream interface (virtual functions that actually get called but do nothing).
Warning: I just made this up, normally I would do something similar to Neil's answer - have a macro meaning "only do this in debug builds", so that it is explicit in the source what is debugging code, and what isn't. Some things I don't actually want to abstract.
Neil's macro also has the property that it absolutely, definitely, doesn't evaluate its arguments in release. In contrast, even with my template inlined, you will find that sometimes:
debug << someFunction() << "\n";
cannot be optimised to nothing, because the compiler doesn't necessarily know that someFunction() has no side-effects. Of course if someFunction() does have side effects then you might want it to be called in release builds, but that's a peculiar mixing of logging and functional code.
Like others have said the most performant way is to use the preprocessor. Normally I avoid the preprocessor, but this is about the only valid use I have found for it bar protecting headers.
Normally I want the ability to turn on any level of tracing in release executables as well as debug executables. Debug executables get a higher default trace level, but the trace level can be set by configuration file or dynamically at runtime.
To this end my macros look like
#define TRACE_ERROR if (Debug::testLevel(Debug::Error)) DebugStream(Debug::Error)
#define TRACE_INFO if (Debug::testLevel(Debug::Info)) DebugStream(Debug::Info)
#define TRACE_LOOP if (Debug::testLevel(Debug::Loop)) DebugStream(Debug::Loop)
#define TRACE_FUNC if (Debug::testLevel(Debug::Func)) DebugStream(Debug::Func)
#define TRACE_DEBUG if (Debug::testLevel(Debug::Debug)) DebugStream(Debug::Debug)
The nice thing about using an if statement is that there is no cost to for tracing that is not output, the tracing code only gets called if it will be printed.
If you don't want a certain level to not appear in release builds use a constant that is available at compile time in the if statement.
#ifdef NDEBUG
const bool Debug::DebugBuild = false;
#else
const bool Debug::DebugBuild = true;
#endif
#define TRACE_DEBUG if (Debug::DebugBuild && Debug::testLevel(Debug::Debug)) DebugStream(Debug::Debug)
This keeps the iostream syntax, but now the compiler will optimise the if statement out of the code, in release builds.
#ifdef RELEASE
#define DBOUT( x )
#else
#define DBOUT( x ) x
#endif
Just use this in the actual ostream operators themselves. You could even write a single operator for it.
template<typename T> Debugstream::operator<<(T&& t) {
DBOUT(ostream << std::forward<T>(t);) // where ostream is the internal stream object or type
}
If your compiler can't optimize out empty functions in release mode, then it's time to get a new compiler.
I did of course use rvalue references and perfect forwarding, and there's no guarantee that you have such a compiler. But, you can surely just use a const ref if your compiler is only C++03 compliant.
#iain: Ran out of room in the comment box so posting it here for clarity.
The use of if statements isn't a bad idea! I know that if statements in macros may have some pitfalls so I'd have to be especially careful constructing them and using them. For example:
if (error) TRACE_DEBUG << "error";
else do_something_for_success();
...would end up executing do_something_for_success() if an error occurs and debug-level trace statements are disabled because the else statement binds with the inner if-statement. However, most coding styles mandate use of curly braces which would solve the problem.
if (error)
{
TRACE_DEBUG << "error";
}
else
{
do_something_for_success();
}
In this code fragment, do_something_for_success() is not erroneously executed if debug-level tracing is disabled.
Related
I'm reading Inside The C++ Object Model and find confused about inline function expansion.
In general, each local variable within the inline function must be introduced into the enclosing block of the call
as a uniquely named variable. If the inline function is expanded multiple times within one expression, each
expansion is likely to require its own set of the local variables. If the inline function is expanded multiple
times in discrete statements, however, a single set of the local variables can probably be reused across the
multiple expansions.
Here, what does it mean to expand inline function multiple times in discrete statements and how could that happen? Can anyone raise a concrete example to apply this?
I had some trouble to handle the term discrete statement (especially because it has been emphasized multiple times). I tried to find something like a clear definition (by google) but I couldn't. Thus, I decided to read this literally as one statement (with discrete in the sense of separate).
Denoting a function inline is just a hint to the compiler that the programmer would like to have the function body inserted directly at every "call point" (instead of simply calling the function). Actually, the compiler decides whether the function is really inlined. (It might be even inlined at one point of call but become a function call at another point.) If a macro is used instead of the inline function, the inline requirement would be granted (as macro expansion is actually nothing else than text replacement). Of course, macros have a lot of limitations which inline functions have not. One of them is that inline functions may have local variables.
I made a synthetic example. It's not code "ready for production" but it hopefully helps to illustrate the topic:
#include <iostream>
using namespace std;
inline int absValue(int a)
{
int mB = -a;
return a < 0 ? mB : a;
}
int main()
{
int value;
// use input to prevent compile-time computation
cout << "input: " << flush;
cin >> value;
// multiple usages of absValue()
cout << "value: " << value << endl
<< "absValue(value): "
<< absValue(value)
<< endl
<< "absValue(-value): "
<< absValue(-value)
<< endl;
// done
return 0;
}
The second output statement calls function absValue() multiple times where the call should be inlined. I imagine it like:
// multiple usages of absValue()
cout << "value: " << value << endl
<< "absValue(value): "
<< {
int mB = -(value);
return (value) < 0 ? mB : (value);
}
<< endl
<< "absValue(-value): "
<< {
int mB = -(-value);
return (-value) < 0 ? mB : (-value);
}
<< endl;
There are two occurrences of mB in this statement. On one hand, these are two separate local variables. On the other hand, they may share the same storage on stack as they are used consecutively. (They might not share the same storage if the compiler optimization introduces some kind of code re-ordering which results in interleaving of the first and second expansion of absValue().)
This whole explanation is rather theoretically. Practically, the compiler will hopefully put mB into a register or even optimize most of the code away.
I fiddled a little bit with godbolt to illustrate it further. Finally, I must admit that it proofs essentially my last paragraph above.
I have such simple macro which has two argument:
#define DO_SOMETHING(__X__ , __Y__) \
do{ \
__X__;\
__Y__;\
} while (0);
Here there are three examples of how I use this macro, besides console output:
DO_SOMETHING(cout << "Part 1";); //=> Part1 //NoErr
DO_SOMETHING(cout << "Part 1"; , cout << "Part 2";); //=> Part1 Part2
DO_SOMETHING(cout << "Part 1";, cout << "Part 2";, cout << "Part3";); //=> Part1 Part2 //NoErr
I think it's due to the way comma , is interpreting in macro.
Question: However, I'd like to see a compile-time error for case 1 and 3. How can I achieve it?
PS: I can't use function instead since I need the context! For example the first parameter may be a return; statement.
EDIT: Real macro is not such easy. In fact, we have a repetitive switch-case all over project that we want to have a mechanism to check if we handle are cases in all switches. we could do it by (1) Polymorphism (2) function-call. solution (1) is not applicable since we will have a ultra-huge class with hardly cohesion codes, and solution (2) is not possible because we need Context.
PS: We do need to compiler on both Visual Studio and GCC, as well as xCode environment.
I have this snippet of C++ code from an exam. We are just suppose to write out what the output of the program is, I assumed the output would be '20', but the output is '10'. Why is this?
#define func(x) (x*x)-x
int i=3;
int main() {
cout << func(i+2) << endl;
}
If I put the i+2 in brackets like so:
cout << func( (i+2) ) << endl;
The output is '20' as assumed it would be.
How does C++ process this code that makes it return 10 not 20?
That's just how macros work. It's pure text substitution. So func(i+2) expands as:
(i+2*i+2)-i+2
which is to say:
2*i + 4
This is why typically macros would be written by excessively parenthesizing the arguments:
#define func(x) (((x)*(x))-(x))
But really, this is why you should strongly prefer functions to macros. While parenthesizing the arguments would fix the usage in func(i+2), it still wouldn't fix the usage in func(++i) - which while being a straightforward expression if func were a function is undefined behavior with the macro.
Because the brackets aren't there.
The macro expands to
(i+2*i+2)-i+2
And it all goes wrong from there. An inline function instead of a macro would just work.
Lessons to be learned: (1) Always parenthesise inside macro definitions. (2) DON'T USE MACROS IN C++!
Our project uses a macro to make logging easy and simple in one-line statements, like so:
DEBUG_LOG(TRACE_LOG_LEVEL, "The X value = " << x << ", pointer = " << *x);
The macro translates the 2nd parameter into stringstream arguments, and sends it off to a regular C++ logger. This works great in practice, as it makes multi-parameter logging statements very concise. However, Scott Meyers has said, in Effective C++ 3rd Edition, "You can get all the efficiency of a macro plus all the predictable behavior and type safety of a regular function by using a template for an inline function" (Item 2). I know there are many issues with macro usage in C++ related to predictable behavior, so I'm trying to eliminate as many macros as possible in our code base.
My logging macro is defined similar to:
#define DEBUG_LOG(aLogLevel, aWhat) { \
if (isEnabled(aLogLevel)) { \
std::stringstream outStr; \
outStr<< __FILE__ << "(" << __LINE__ << ") [" << getpid() << "] : " << aWhat; \
logger::log(aLogLevel, outStr.str()); \
}
I've tried several times to rewrite this into something that doesn't use macros, including:
inline void DEBUG_LOG(LogLevel aLogLevel, const std::stringstream& aWhat) {
...
}
And...
template<typename WhatT> inline void DEBUG_LOG(LogLevel aLogLevel, WhatT aWhat) {
... }
To no avail (neither of the above 2 rewrites will compile against our logging code in the 1st example). Any other ideas? Can this be done? Or is it best to just leave it as a macro?
Logging remains one of the few places were you can't completely do away with macros, as you need call-site information (__LINE__, __FILE__, ...) that isn't available otherwise. See also this question.
You can, however, move the logging logic into a seperate function (or object) and provide just the call-site information through a macro. You don't even need a template function for this.
#define DEBUG_LOG(Level, What) \
isEnabled(Level) && scoped_logger(Level, __FILE__, __LINE__).stream() << What
With this, the usage remains the same, which might be a good idea so you don't have to change a load of code. With the &&, you get the same short-curcuit behaviour as you do with your if clause.
Now, the scoped_logger will be a RAII object that will actually log what it gets when it's destroyed, aka in the destructor.
struct scoped_logger
{
scoped_logger(LogLevel level, char const* file, unsigned line)
: _level(level)
{ _ss << file << "(" << line << ") [" << getpid() << "] : "; }
std::stringstream& stream(){ return _ss; }
~scoped_logger(){ logger::log(_level, _ss.str()); }
private:
std::stringstream _ss;
LogLevel _level;
};
Exposing the underlying std::stringstream object saves us the trouble of having to write our own operator<< overloads (which would be silly). The need to actually expose it through a function is important; if the scoped_logger object is a temporary (an rvalue), so is the std::stringstream member and only member overloads of operator<< will be found if we don't somehow transform it to an lvalue (reference). You can read more about this problem here (note that this problem has been fixed in C++11 with rvalue stream inserters). This "transformation" is done by calling a member function that simply returns a normal reference to the stream.
Small live example on Ideone.
No, it is not possible to rewrite this exact macro as a template since you are using operators (<<) in the macro, which can't be passed as a template argument or function argument.
We had the same issue and solved it with a class based approach, using a syntax like
DEBUG_LOG(TRACE_LOG_LEVEL) << "The X value = " << x << ", pointer = " << *x << logger::flush;
This would indeed require to rewrite the code (by using a regular expression) and introduce some class magic, but gives the additional benefit of greater flexibiliy (delayed output, output options per log level (to file or stdout) and things like that).
The problem with converting that particular macro into a function is that things like "The X value = " << x are not valid expressions.
The << operator is left-associative, which means something in the form A << B << C is treated as (A << B) << C. The overloaded insertion operators for iostreams always return a reference to the same stream so you can do more insertions in the same statement. That is, if A is a std::stringstream, since A << B returns A, (A << B) << C; has the same effect as A << B; A << C;.
Now you can pass B << C into a macro just fine. The macro just treats it as a bunch of tokens, and doesn't worry about what they mean until all the substituting is done. At that point, the left-associative rule can kick in. But for any function argument, even if inlined and templated, the compiler needs to figure out what the type of the argument is and how to find its value. If B << C is invalid (because B is neither a stream nor an integer), compiler error. Even if B << C is valid, since function parameters are always evaluated before anything in the invoked function, you'll end up with the behavior A << (B << C), which is not what you want here.
If you're willing to change all the uses of the macro (say, use commas instead of << tokens, or something like #svenihoney's suggestion), there are ways to do something. If not, that macro just can't be treated like a function.
I'd say there's no harm in this macro though, as long as all the programmers who have to use it would understand why on a line starting with DEBUG_LOG, they might see compiler errors relating to std::stringstream and/or logger::log.
If you keep a macro, check out C++ FAQ answers 39.4 and 39.5 for tricks to avoid a few nasty ways macros like this can surprise you.
To print debug messages in my program, I have a that can be used like this:
DBG(5) << "Foobar" << std::endl;
5 means the level of the message, if the debug level is smaller than 5, it won't print the message. Currently it is implemented like:
#define DBG(level) !::Logger::IsToDebug((level)) ? : ::Logger::Debug
Basically IsToDebug checks if the message should be printed, and returns true when it should. Logger::Debug is an std::ostream. This works with gcc and clang too, however clang generates expression result unused warnings. According to this email this doesn't like to change either.
Prefixing it with (void) doesn't work, it will only cast the thing before the ?, resulting in a compilation error (void can't be converted to bool, obviously). The other problem with this syntax that it uses a gcc extension.
Doing things like #define DBG(x) if (::Logger::IsToDebug((x))) ::Logger::Debug solves the problem, but it's a sure way break your program (if (foo) DBG(1) << "foo"; else ...) (and I can't put the whole thing into a do { ... } while(0) due to how the macro is called.)
The only more or less viable solution I came up with is this (assuming IsToDebug returns either 0 or 1):
#define DBG(level) for(int dbgtmpvar = ::Logger::IsToDebug((level)); \
dbgtmpvar > 0; --dbgtmpvar) ::Logger::Debug
Which seems like an overkill (not counting it's runtime overhead)
I think you should use ternary operator, as it is defined in the Standard, rather than compiler extension. To use the Standard ternary operator, you've to provide the second expression as well. For that, you can define a stream class, deriving from std::ostream which doesn't print anything to anywhere. Object of such a class can be used as second expression.
class oemptystream : std::ostream
{
//..
};
extern oemptystream nout; //declaration here, as definition should go to .cpp
then
#define DBG(level) ::Logger::IsToDebug((level))? nout : ::Logger::Debug
Now if you use this macro, then at runtime, the expression would reduce to either this:
nout << "message";
Or this,
::Logger::Debug << "message";
Either way, it is pretty much like this:
std::cout << "message";
So I hope it shouldn't give compiler warning.