57

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++.

Community
  • 1
  • 1
Maël Nison
  • 7,055
  • 7
  • 46
  • 77

7 Answers7

77

You need a custom streambuf.

class NullBuffer : public std::streambuf
{
public:
  int overflow(int c) { return c; }
};

You can then use this buffer in any ostream class

NullBuffer null_buffer;
std::ostream null_stream(&null_buffer);
null_stream << "Nothing will be printed";

streambuf::overflow is the function called when the buffer has to output data to the actual destination of the stream. The NullBuffer class above does nothing when overflow is called so any stream using it will not produce any output.

john
  • 7,897
  • 29
  • 27
  • 23
    One could create a convenience class `class NullStream : public std::ostream { public: NullStream() : std::ostream(&m_sb) {} private: NullBuffer m_sb; };`, which simplifies the usage to `NullStream null_stream; null_stream << ...` – Sjoerd Aug 06 '12 at 10:54
  • 1
    This is great and I suggest adding @Sjoerd's suggestion. I implemented something effectively identical to his, not seeing his comment until just now when I came back to upvote. – sage Feb 23 '17 at 18:47
  • 3
    Just a nit: the function may yield failure turning the stream into failure state (most people won't care, though). To avoid that, you'd want to return the result of `not_eof(). Also, buffering characters is way more effective than calling a `virtual` function on the assumed to be unlikely path, i.e., I'd also recommend adding setting up a buffer which is just ignored. The overwrite would become `int overflow(int c) { return this->setp(std::begin(d_buffer), std::end(this->d_buffer); std::char_traits::not_eof(c); }`. Similarly, it may be reasonable to overwrite `xsputn()` to do nothing. – Dietmar Kühl Feb 22 '18 at 23:29
  • 4
    @DietmarKühl: Would you mind editing that into the answer, or writing your own? – einpoklum Apr 29 '18 at 17:05
  • @DietmarKühl: writing a proper answer gains some votes and some love! – Liviu Feb 08 '23 at 14:25
39

If this is to disable logging output, your dummyStream would still cause arguments to be evaluated. If you want to minimize impact when logging is disabled, you can rely on a conditional, such as:

#define debugStream \
    if (debug_disabled) {} \
    else std::cerr

So if you have code like:

debugStream << "debugging output: " << foo() << std::endl;

No arguments will be evaluated if debug_disabled is true.

jxh
  • 69,070
  • 8
  • 110
  • 193
  • I'm sorry for necroing this question, but I really need to know this: isn't this answer better than the selected answer performance wise? If debug_disabled is a constant (or even more appropriate, a macro) the compiler might (will?) optimze the else clause away, while using a nullbuffer still causes the stream input to be processed, only to be put into a null device. Is that true? Or not? It'd be awesome if someone could shed some light on this for me. – bobismijnnaam Oct 25 '14 at 17:41
  • 1
    @bobismijnnaam: In fact, someone ripped off this answer in a question asked later in the day I posted it :-). [Link.](http://stackoverflow.com/q/11832960/315052) – jxh Oct 25 '14 at 19:10
  • Hmm, well I went with your answer anyway. The whole NullStream thing seems like too much work. – bobismijnnaam Oct 26 '14 at 11:23
  • That's a great solution, but is it possible to do something similar without having to include `iostream` or to define a throwaway global variable? – Paul Jul 01 '15 at 07:38
  • @Paul: The question was about using an `ostream`, I simply picked one that was already available. To disable logging, the log line has to fall into the `else` side. So, if the goal is to always disable, just use `true` instead of a variable. – jxh Jul 01 '15 at 13:28
  • What I mean is, let's say the line becomes: `if (true) {} else ??? << "debugging output"`. If I have no `ostream`, what can replace `???`? – Paul Jul 01 '15 at 13:31
  • @Paul: That would be a different question, so this answer would not apply. But anything that behaved like a stream would work. – jxh Jul 01 '15 at 13:43
  • @Paul: But I don't understand why you would not use the stream type that you used when debug logging is enabled. That is one of the appealing aspects of this solution. – jxh Jul 01 '15 at 13:52
  • @jxh because it's not defined for a release build. – Paul Jul 01 '15 at 13:55
  • @Paul: Assuming the release version also uses a stream for regular logging, you could just swap that into the macro instead for release builds. However, if the debug stream object is always used in the context of the macro, there are no significant reasons to not leave it enabled in release builds. – jxh Jul 01 '15 at 15:47
4

The basic method voor new stream classes is:

  1. Derive a class from std::streambuf;
  2. Override the virtual functions in that class. This is where the real work is done. In your case, empty implementations should be good enough.
  3. Derive a class from std::ostream with one member, your streambuf class.
  4. The constructor of your streamclass should forward the pointer to that member to the base constructor of std::ostream.

I'm afraid you won't get rid of the formatting step, though.

Hopefully this gives you some pointers; I don't have the time to expand this into a full answer, sorry.

Update: See john's answer for details.

Community
  • 1
  • 1
Sjoerd
  • 6,837
  • 31
  • 44
2

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.

neuviemeporte
  • 6,310
  • 10
  • 49
  • 78
1

There are some answers already but I think it is worth add, yet, another answer building on a comment I made. There are essentially three obvious variations how to create a stream which doesn't produce any data:

  1. The simplest version is to just set the stream into a non-operational state. That doesn't match the specification asking for a working stream, though:

    std::ostream null(nullptr);
    
  2. As mentioned by other answers, deriving a stream from std::sttreambuf and just overriding overflow(int) to return success but other doing nothing:

    struct NullBuffer
        : std::streambuf {
        int overflow(int c) override { return c; }
    };
    

    This is the shortest version to type but as commented already, I don't think this is the fastest approach.

  3. I'd expect a stream buffer actually using a small buffer and also overriding xsputn() to be faster:

    struct NullBuf
        : std::streambuf {
        char buffer[100];
        int overflow(int c) override {
            setp(buffer, buffer + sizeof buffer);
            return c;
        }
        std::streamsize xsputn(const char*, std::streamsize n) override {
            return n;
        }
    };
    

    The reason a small buffer is likely better is that the stream doesn't need to check if the buffer is empty and call virtual function each time. Instead, it would check find that there is buffer and only once in a while call the virtual function.

When running a benchmark for the three versions I get these results:

Running ./bin/clang--2a/nullstream.tsk
Run on (8 X 24 MHz CPU s)
CPU Caches:
  L1 Data 64 KiB
  L1 Instruction 128 KiB
  L2 Unified 4096 KiB (x8)
Load Average: 1.22, 1.52, 2.04
-----------------------------------------------------------
Benchmark                 Time             CPU   Iterations
-----------------------------------------------------------
BM_NullStreambuf        101 ns          101 ns      6883531
BM_NullBuffer          1430 ns         1430 ns       488561
BM_NullBuf              748 ns          748 ns       931309

That is, there is a substantial cost for wanting a non-failing stream rather than simply disabling the stream entirely. Using a buffer and overriding xsput() is a significant performance boost. Of course, these are micro benchmarks using a particular output although I didn't try to be too smart: I included a string (which should use xsputn()) and I included an integer with a bigger number of digits to cause the stream to use the std::ostreambuf_iterator<char> and bypass xsputn(). The full benchmark is included below.

The code was compiled using

clang++ -std=c++2a  -W -Wall -I/usr/local/include -O3 -c -o nullstream.o nullstream.cpp
clang++ -L/usr/local/lib -o nullstream.tsk nullstream.o -lbenchmark -lbenchmark_main

The version of clang is up to date on an M2 MacBook. I haven't run it on other computers or using a different IOStream implementation but I would expect similar results.

#include <benchmark/benchmark.h>
#include <ostream>
#include <limits>

void run_benchmark(benchmark::State& state, std::ostream& out) {
  for (auto _ : state) {
      for (int i{0}; i != 10; ++i) {
          out << (std::numeric_limits<int>::max() - i)
              << "0123456789012345678901234567890123456789"
              << "\n";
      }
  }
}

struct NullBuffer
    : std::streambuf {
    int overflow(int c) override { return c; }
};

struct NullBuf
    : std::streambuf {
    char buffer[100];
    int overflow(int c) override {
    setp(buffer, buffer + sizeof buffer);
        return c;
    }
    std::streamsize xsputn(const char*, std::streamsize n) override {
        return n;
    }
};

static void BM_NullStreambuf(benchmark::State& state) {
  std::ostream null(nullptr);
  run_benchmark(state, null);
}

static void BM_NullBuffer(benchmark::State& state) {
  NullBuffer   buf;
  std::ostream null(&buf);
  run_benchmark(state, null);
}

static void BM_NullBuf(benchmark::State& state) {
  NullBuf      buf;
  std::ostream null(&buf);
  run_benchmark(state, null);
}

BENCHMARK(BM_NullStreambuf);
BENCHMARK(BM_NullBuffer);
BENCHMARK(BM_NullBuf);

BENCHMARK_MAIN();
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
0

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.

antonyjr
  • 61
  • 1
  • 5
  • Compiler will not optimize out function calls. You need to define LOG_START as `if(0){(void)`, and LOG_END as `;}`. This will be optimized out even with optimization disabled - at least gcc is able to so when compiling with -O0. – Daniel Frużyński Nov 20 '19 at 13:05
  • @DanielFrużyński Thanks for the hint. I've made the changes. – antonyjr May 25 '21 at 18:10
-1

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.

solstice333
  • 3,399
  • 1
  • 31
  • 28