70

I'm looking for a std::ostream implementation that acts like /dev/null. It would just ignore anything that is streamed to it. Does such a thing exist in the standard libraries or Boost? Or do I have to roll my own?

svick
  • 236,525
  • 50
  • 385
  • 514
paperjam
  • 8,321
  • 12
  • 53
  • 79

9 Answers9

30

If you have boost, then there's a null ostream & istream implementation available in boost/iostreams/device/null.hpp . The gist of it:

#include "boost/iostreams/stream.hpp"
#include "boost/iostreams/device/null.hpp"
...
boost::iostreams::stream< boost::iostreams::null_sink > nullOstream( ( boost::iostreams::null_sink() ) );
...
Ylisar
  • 4,293
  • 21
  • 27
28

The simplest solution is just to use an unopened std::ofstream. This will result in an error state in the stream, but most outputters won't check this; the usual idiom is to leave the check to the end, after the close (which would put it in code you wrote, where you know that the stream should be invalid).

Otherwise, it's pretty straight forward to implement: just create a streambuf which contains a small buffer, and sets it up in overflow (always returning success). Note that this will be slower than the unopened file, however; the various >> operators will still to all of the conversion (which they don't do if the stream has an error state).

EDIT:

class NulStreambuf : public std::streambuf
{
    char                dummyBuffer[ 64 ];
protected:
    virtual int         overflow( int c ) 
    {
        setp( dummyBuffer, dummyBuffer + sizeof( dummyBuffer ) );
        return (c == traits_type::eof()) ? '\0' : c;
    }
};

It's usual to provide a convenience class derived from istream or ostream as well, which will contain an instance of this buffer which it uses. Something along the lines of:

class NulOStream : private NulStreambuf, public std::ostream
{
public:
    NulOStream() : std::ostream( this ) {}
    NulStreambuf* rdbuf() const { return this; }
};

Or you can just use an std::ostream, passing the address of the streambuf to it.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 5
    The original idea (unopened `std::ofstream`) works really cool. Is it reliable / standard compliant, and not likely to cause problems (exceptions?) in the future? I'm a bit worried about the performance, but I guess the only waste is the `<<` operators being called, checking one `if` and returning? – Tomasz Gandor May 20 '16 at 10:56
  • @TomaszGandor: _"Is it reliable / standard compliant, and not likely to cause problems (exceptions?) in the future?"_ [Well, sometimes..](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53984) – Lightness Races in Orbit Jun 17 '19 at 22:54
22

I know this is very old thread, but I would like to add this to anyone who is looking for the same solution without boost and the fastest one.

I combined three different proposals above and one writing directly to /dev/null (so it involves kernel.)

Surprisingly the NullStream that got the most votes performed the worst.

Here are results for 100,000,000 writes:

a) /dev/null : 30 seconds
b) NullStream: 50 seconds
c) badbit    : 16 seconds (the winner in speed, but cannot test for errors!)
d) boost     : 25 seconds (the ultimate winner)

Here is the test code

#include <iostream>
#include <fstream>
#include <time.h>
#include <boost/iostreams/stream.hpp>

class NullStream : public std::ostream {
    class NullBuffer : public std::streambuf {
    public:
        int overflow( int c ) { return c; }
    } m_nb;
public:
    NullStream() : std::ostream( &m_nb ) {}
};

int test( std::ostream& ofs, const char* who ) {
    const time_t t = time(NULL);
    for ( int i = 0 ; i < 1000000000 ; i++ )
        ofs << "Say the same" ;
    std::cout << who << ": " << time(NULL) - t << std::endl;
}

void devnull() {
    std::ofstream ofs;
    ofs.open( "/dev/null", std::ofstream::out | std::ofstream::app );
    test(ofs, __FUNCTION__);
    ofs.close();
}

void nullstream() {
    NullStream ofs;
    test(ofs, __FUNCTION__);
}

void badbit() {
    std::ofstream ofs;
    ofs.setstate(std::ios_base::badbit);
    test(ofs, __FUNCTION__);
}

void boostnull() {
    boost::iostreams::stream< boost::iostreams::null_sink > nullOstream( ( boost::iostreams::null_sink() ) );
    test(nullOstream, __FUNCTION__);
}

int main() {
    devnull();
    nullstream();
    badbit();
    boostnull();
    return 0;
}

EDIT

The fastest solution - where we use badbit - has a downside. If the program checks if the output is successfully written - and I have no idea why the program should not do that - then it will fail because of this badbit. Therefore, the runner up - boost - is the winner.

Grzegorz
  • 3,207
  • 3
  • 20
  • 43
  • 1
    /dev/null isn't portable to Windows, I think. I tried ofs.open("") and it didn't write any files so maybe that is a better option? – Eyal May 31 '18 at 15:01
  • @Eyal - I was focusing on /dev/null as it was in the object of the question. I believe in Windows there is 'nil' but I don't know how to use it from the development point of view... – Grzegorz May 31 '18 at 16:41
  • It's "nul" on Windows: https://stackoverflow.com/questions/313111/is-there-a-dev-null-on-windows – gerardw Jan 12 '19 at 12:27
22

If you set badbit on a stream it won't output anything:

#include <iostream>

int main() {
    std::cout << "a\n";

    std::cout.setstate(std::ios_base::badbit);
    std::cout << "b\n";

    std::cout.clear();
    std::cout << "c\n";
}

Outputs:

a
c
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 5
    @MatthieuM. Using `std::cout << std::boolalpha` is also a modifying of a global variable. Using `std::cout << anything` also. I don't understand your point. – Notinlist Nov 14 '14 at 19:35
  • 1
    Although you are right about that in a general case there is a collision of interests between parts of the same program if one or both of them change the configuration of `std::cout`. But then why is it configurable? If I were in the past and I would design C++, I would separate output filtering from output stream, something like `std::out_filter of; of << std::boolalpha << std::whatever_option; std::out_proxy(std::cout, of) << "something";`. – Notinlist Nov 14 '14 at 20:00
  • 2
    @Notinlist: I have a lot of *whys* about the design of `ostream`; it was early C++ by then, where global variables were still common place and few experience had been gathered, and it shows... I find it awkward to conflate formatting and where to output, for example, I find it even awkward to *inject* formatters into the stream rather than using the *Decorator* pattern, etc... but I have the benefit of hindsight. – Matthieu M. Nov 15 '14 at 11:54
5

Following the @user5406764's answer, it is possible to skip any actual operations by overloading the global << operator. The solution should be cross-platform and the fastest one.

#include <iostream>

class NullStream : public std::ostream {
public:
  NullStream() : std::ostream(nullptr) {}
  NullStream(const NullStream &) : std::ostream(nullptr) {}
};

template <class T>
const NullStream &operator<<(NullStream &&os, const T &value) { 
  return os;
}

int main() {
  auto null = NullStream();
  std::cerr << "a" << std::endl;
  null << "b" << std::endl;
  std::cerr << "c" << std::endl;
}

Output:

a
c
Vlad Faust
  • 542
  • 6
  • 18
3

You can do it without third-party libraries. Just set the associated stream buffer to nullptr using rdbuf and your job is done

std::cout << "Hello,";
std::cout.rdbuf(nullptr);
std::cout << " world!\n";

Online example here.

cbuchart
  • 10,847
  • 9
  • 53
  • 93
  • This is good. But just note that the same problem as badbit stays:When using the rdbuf, if the stream buffer is a null pointer, the function automatically sets the badbit error state flags (which may throw an exception if member exceptions has been passed badbit). [http://www.cplusplus.com/reference/ios/ios/rdbuf/] – shaheen g Sep 05 '20 at 03:53
  • Will that let me track the number of characters I've written? – einpoklum May 28 '22 at 17:00
  • @einpoklum I suppose you could create your own `streambuf` and overload the `xsputn` method. As a PoC: http://coliru.stacked-crooked.com/a/a8ed0e19ec9cf1b7 – cbuchart Jun 16 '22 at 12:35
  • @einpoklum I think this was not part of OP's question, so publishing in this answer is out-of-scope. If you want please publish a question and I'll be glad to post it there. – cbuchart Jun 16 '22 at 14:04
  • @cbuchart: You're right, sorry. – einpoklum Jun 16 '22 at 14:12
1
struct NullStream // only subclass std::stream if you must
{
    template<typename T>
    NullStream& operator<<(T const&) { return *this; }
};

NullStream TheNullStream; // There's your global instance
user5406764
  • 1,627
  • 2
  • 16
  • 23
  • 4
    Please edit your answer and add some context by explaining how your answer solves the problem, instead of posting code-only answer. [From Review](https://stackoverflow.com/review/low-quality-posts/24962358) – Pedram Parsian Dec 28 '19 at 19:00
  • I've been trying to work out a solution like this, so that the optimizer can eliminate debug logging in non-debug builds. Unfortunately, the stream insertion operator template shown here doesn't match manipulators like `std::endl`. – Adrian McCarthy Jul 24 '20 at 23:32
0

As for me the simplest way would be:

#include <fstream>

std::ostream* out = &std::cout;

std::ostream* nullstream() {
    static std::ofstream os;
    if (!os.is_open())
        os.open("/dev/null", std::ofstream::out | std::ofstream::app);
    return &os;
}

int main() {
    *out << "Normal output\n";

    out = nullstream();
    *out << "Will not visible\n";

    out = &std::cout;
    *out << "Back again\n";

    return 0;
}

Or use 'badbit' flag instead of '/dev/null' in 'nullstream' function as described above.

std::ostream* nullstream() {
    static std::ofstream os;
    static bool flag_set = false;
    if (!flag_set) {
        os.setstate(std::ios_base::badbit);
        flag_set = true;
    }
    return &os;
}
0

May this solution overcomes the performance issue without using boost:

#include <ostream>

class dev0_buffer : public std::streambuf
{
   //called usually for n-characters
   std::streamsize xsputn (const char* s, std::streamsize n) override { return n; }

   //may not required due it's not called anymore
   int overflow (int c)  override { return c; } 
} nirwana;

class dev0_stream : public std::ostream
{
   public:
    dev0_stream(): std::ostream(&nirwana){}
};
Karsten
  • 11
  • 1