Standard no-op output stream

Viewed 18873

Is there a way to create an ostream instance which basically doesn't do anything ?

For example :

std::ostream dummyStream(...);
dummyStream << "Nothing will be printed";

I could just create an ostringstream, but data will be buffered (and I really don't want to make anything with them, so it adds a useless overhead).

Any idea ?

[edit] Found this related question which suits my needs. However, I think it could be useful to have a answer saying how to create a valid (no badbit) output stream with standard c++.

6 Answers

For runtime-controllable redirection of log messages, a self-contained solution combining the ideas of john and Sjoerd:

class DebugStream {
private:
    class NullStream : public std::ostream {
    private:
        class NullBuffer : public std::streambuf {
        public:
            int overflow(int c) override { return c; }
        } buffer_;
    public:
        NullStream() : std::ostream(&buffer_) {}
    } null_;

    std::ostream &output_;
    bool enabled_;

public:
    DebugStream(std::ostream &output = std::cout) : output_(output), enabled_(false) {}
    void enable(const bool enable) { enabled_ = enable; }

    template <typename T> std::ostream& operator<<(const T &arg) {
        if (enabled_) return output_ << arg;
        else return null_ << arg;
    }
};

extern DebugStream debug_stream;
#define TRACE_ENABLE(x) debug_stream.enable(x)
#define TRACELN(x) debug_stream << x << std::endl
#define TRACE(x) debug_stream << x

Then you can do stuff like:

TRACELN("The value of x is " << x " and the value of y is " << y);

It would also be easy to just remove the trace statements from a release version completely with #define the trace macros to empty statements.

You still need to define debug_stream somewhere global, though.

If you are concerned about the overhead of your debugger then you can write a very simple code to void out your debug messages on compilation. This is what I use for my c++ programs.

#include <iostream>
#define DEBUGGING // Define this in your config.h or not.
#ifdef DEBUGGING
/*
 * replace std::cout with your stream , you don't need to
 * worry about the context since macros are simply search
 * and replace on compilation.
 */
#define LOG_START std::cout <<
#define LOG_REDIR <<
#define LOG_END   << std::endl;
#else
#define LOG_START if(0){(void)
#define LOG_REDIR ;(void)
#define LOG_END   ;}
#endif // DEBUGGING

int main(){
LOG_START "This is a log message " LOG_REDIR "Still a log message." LOG_END;
return 0;
}

Now when making your project , check if the user wants to disable the logging , if so , just undefine the DEBUGGING macro or whatever macro you choose to check for.

Now your code will be optimized by the compiler , Because when anything is voided , it will not be included in the resulting binary(most of the time) , making the binary production ready.

I needed a null stream that was of type ostream so I did something like this:

struct NullStream: public stringstream {
   NullStream(): stringstream() {}
};

template<typename T>
void operator<<(const NullStream&, const T&) {}

Application code:

NullStream ns;
ostream &os = ns;
os << "foo";

The real issue is all the public methods that I inherited but don't care about so I just didn't bother overriding them.

Related