Jump to content
  • Advertisement
Sign in to follow this  
SirLuthor

Removing code from Release builds

This topic is 4853 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hell once again! I bring my queries, to lay at your feet, in hopes of answers to apply [smile] Anyway, here's the deal. I've got a console class, which opens up a console, and defined a number of writing operators (<< at the moment) for different types. So a typical line logged to the console would look about like logging a line to cout, or an fstream, or whatever. Now, my problem lies in wishing to remove this code entirely in release builds, that is, have the preprocessor remove it if possible, otherwise, have no overhead in the runtime code. Now, is there any way you people know to do this? I've tried a number of things with the preprocessor, such as __noop, etc, but it's not doing anything good for me, and at the moment, I have a terrible hack, which is surrounding the operators and the arguments all in one macro. It looks bad, it doesn't fit in with C++ syntax, etc. Now, again, is there a better way to do this? Would you personally find it usable to use a function for writing to the console, instead of the average string of ' << "someString" << someInt << "SomeOtherString!" << endl;' Iðm personally fine with that method, but when I distribute this, I don't want to alienate lots of people with that feature. Plus, if I do things that way, you can't define your own writing operators. Anyway, any thoughts on how to improve this problem would be much appreciated. Thanks! Also, just for the record, if there is an inlined function call, with no body at all to the function ie. no code, just a return value) is there any overhead when calling it?

Share this post


Link to post
Share on other sites
Advertisement
Have a look at John Torjo's logging library he uses a trick with variables declared in an if statement having scope over the whole statement.

However even this solution has a price (albeit quite small), which from memory is something like one memory allocation an if statement and a few pointer copies and dereferences.

I don't believe a better solution is possible without having the whole statement within a macro (which is what you've got) so it comes down to a tradeoff between ease of use and performance.


/* Simple Case (just log default information) */
LOG( logger );
/* OR */
/* Message case (default + extras) */
LOG( logger ) << "foo" << "bar" << "blah" << endl;




The log macro with the stream operators appended expands to:


if( SomeStreamClass stream = logger.getTemporaryStream() )
stream;
/* OR */
if( SomeStreamClass stream = logger.getTemporaryStream() )
stream << "foo" << "bar" << "blah" << endl;




The reason that the assignment within the if is valid is that SomeStreamClass has a conversion to bool. The destructor of SomeStreamClass also writes to the logs, and will be triggered when the if statement ends (after all of the stream operations have executed). Note that the destructor of SomeStreamClass should have a 'try{ } catch(...) {}' block to ensure that it is non-throwing.

Share this post


Link to post
Share on other sites
Quote:
Original post by SirLuthor
Also, just for the record, if there is an inlined function call, with no body at all to the function ie. no code, just a return value) is there any overhead when calling it?


Compiler dependant, but I would throw out any compiler where this is the case. I can imagine C compilers from 1985 doing this, that's about it.

The cleanest way for random interspersed debugging code is probably this:

#ifdef DEBUG
const bool debug = true;
#else //def DEBUG
const bool debug = false;
#endif //ndef DEBUG

...

int main () {
if ( debug ) clog << "Debug: I like pie" << endl;
}


Modern compilers are smart enough that they'll go "Oh, debug is a (nonvolatile) constant. That means I don't really need to have this be a conditional. Hmm - this is allways [true/false]. That means I [do/do not] need to include the body.

And yet, it still preforms syntax checking :-).

You can also do finer grained debugging - e.g.:

const bool debug_gadget_13 = true;
const bool debug_gadget_14 = false;

if ( debug_gadget_13 ) clog << "Debug: Oh noes, gadget 13 is FUBAR again?" << endl;

Share this post


Link to post
Share on other sites
Alright, thanks, that helps, but I do have another question along the lines of using those constant variables and such, namely, is there any way to test against on of those variables in an #if statement? I've been messing around with that, and using const ints instead of #defines for control variables, but I'm a bit stuck here. Here's what I'm trying to do.. Basically, when a certain value was defined (this was before I started moving to variables instead) an extern global console object is created. However, if it is not defined, it should not be created, but to have that occur, I need to be able to physically remove the code from the file. Now, the preprocessor is of course clearly made for just this sort of thing, but I can't get it to evaluate constant variables.

So I'm in a fix. And yes, I know there are other ways I can do the whole console-on/console-not-on thing, but eventually, this problem will come up again without a doubt, although in another form. So I'd really appreciate it if someone could point out, if it's possible at all, to do what I'm talking about. Thanks!

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
class Logger
{
Logger() {}
~Logger() {}

#ifdef _DEBUG
template Logger &operator <

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
class Logger
{
Logger() {}
~Logger() {}

#ifdef _DEBUG
template <class T> Logger &operator << (const T &val)
{
//Logging stuff
return *this;
}
#else
template <class T> Logger &operator << (const T &val)
{
return *this;
}
#endif
};


Can someone please kill my bad post above? Thanks.

Share this post


Link to post
Share on other sites
Code dupliation sucks:

class Logger
{
Logger() {}
~Logger() {}

template <class T> Logger &operator << (const T &val)
{
#ifdef _DEBUG
//Logging stuff
#endif
return *this;
}
};



Boost has a preprocessor library that you may look into. I've never looked into it, but glancing through other boost header files it seems to offer some interesting functionality. Although I can say that the preprocessor almost certainly can't consider variables except possibly using a compiler specific extension...it knows nothing about the underlying programming language, it just messes with raw text files.

CM

Share this post


Link to post
Share on other sites
Thanks Connor, that was what I had thought (was afraid of). Oh well, looks like I'll have to modify my two-minute design again [grin]

Share this post


Link to post
Share on other sites
Quote:
Original post by SirLuthor
Alright, thanks, that helps, but I do have another question along the lines of using those constant variables and such, namely, is there any way to test against on of those variables in an #if statement? I've been messing around with that, and using const ints instead of #defines for control variables, but I'm a bit stuck here. Here's what I'm trying to do.. Basically, when a certain value was defined (this was before I started moving to variables instead) an extern global console object is created. However, if it is not defined, it should not be created, but to have that occur, I need to be able to physically remove the code from the file. Now, the preprocessor is of course clearly made for just this sort of thing, but I can't get it to evaluate constant variables.

So I'm in a fix. And yes, I know there are other ways I can do the whole console-on/console-not-on thing, but eventually, this problem will come up again without a doubt, although in another form. So I'd really appreciate it if someone could point out, if it's possible at all, to do what I'm talking about. Thanks!


You could use template specialization.

template < bool debug > class logger;

template <>
class logger< true > {
std::ostream & os;
public:
void log( const std::string & data ) const {
os << data << endl;
}
};

template <>
class logger< false > {
public:
//no log decleration if we want a compile error when attempted to be used
void log( const std::string & data ) const; //if we want a linker error
void log( const std::string & data ) const {
//noop: if we want it just not to happen
}
};

logger< debug > my_debug_logger;

Share this post


Link to post
Share on other sites
I'm using something I got from GPG I think.

It relies on shortcuts when evaluating something. The idea is that when you have

false && DoFunc();

DoFunc is never called. So in your case you'd have something like:

#define DEBUG_COUT DEBUG && cout

DEBUG_COUT << "output" << endl;

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!