Is There a Null Std::Ostream Implementation in C++ or Libraries

Is there a null std::ostream implementation in C++ or libraries?

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() ) );
...

Standard no-op output stream

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.

Is it valid to construct an `std::ostream` from a null buffer?

Yes, it is legal and well-defined to instantiate that stream. You can safely swap it with another stream, or give it a new pointer (this time to an extant buffer) at a later time. The output operation itself is indeed a no-op.

Here's why:

  1. The construction has no non-null precondition, and has only this postcondition:

    [C++11: 27.7.3.2/2]: Postcondition: rdbuf() == sb.

  2. Interestingly, it makes an explicit point that no operation shall be performed on sb within the constructor:

    [C++11: 27.7.3.2/4]: Remarks: Does not perform any operations on rdbuf().

  3. But note also:

    [C++11: 27.7.3.2/1]: Effects: Constructs an object of class basic_ostream, assigning initial values to the base class by calling basic_ios<charT,traits>::init(sb) (27.5.5.2).

  4. That init(sb) call has the effect of setting badbit on the stream when sb is NULL:

    [C++11: 27.5.5.2/3]: Postconditions: The postconditions of this function are indicated in Table 128.

    [C++11: Table 128]: [..] rdstate(): goodbit if sb is not a null pointer, otherwise
    badbit. [..]

  5. The output operation would result in actions equivalent to dereferencing a null pointer:

    [C++11: 27.7.3.1/2]: Two groups of member function signatures share common properties: the formatted output functions (or inserters) and the unformatted output functions. Both groups of output functions generate (or insert) output characters by actions equivalent to calling rdbuf()->sputc(int_type). They may use other public members of basic_ostream except that they shall not invoke any virtual members of rdbuf() except overflow(), xsputn(), and sync().

    except it never gets this far, because for basic_ostream::sentry construction:

    [C++11: 27.7.3.4/3]: If, after any preparation is completed, os.good() is true, ok_ == true otherwise, ok_ == false.

    and, for explicit operator basic_ostream::sentry::bool() const;:

    [C++11: 27.7.3.4/5]: Effects: Returns ok_.

    and:

    [C++11: 27.7.3.7/1]: Each unformatted output function begins execution by constructing an object of class sentry. If this object returns true, while converting to a value of type bool, the function endeavors to generate the requested output. [..]

    …the implication being that no output operation takes place at all when badbit is already set.

This was also the case in C++03.

Default NULL value for an ofstream

I want applications that were using myfun to still work with no modifications.

If so, use an ofs with default nullptr

int myfun(const int a, ofstream *ofs = nullptr)
{
if (ofs != nullptr)
{
// (*ofs) << ... ;
}

// ...
}

You can't use a reference parameter ofstream& ofs for such function because a reference cannot be null.

iostream equivalent to snprintf(NULL, 0, format_string, args...)

Rather than a custom std::ostream it might be easier -- and perhaps more flexible -- to implement a custom std::streambuf that can then be used with any std::ostream.

#include <streambuf>

template <class CharT, class Traits = std::char_traits<CharT>>
struct counting_streambuf: std::basic_streambuf<CharT, Traits> {
using base_t = std::basic_streambuf<CharT, Traits>;
using typename base_t::char_type;
using typename base_t::int_type;

std::streamsize count = 0;

std::streamsize xsputn(const char_type* /* unused */, std::streamsize n)
override
{
count += n;
return n;
}

int_type overflow(int_type ch)
override
{
++count;
return ch;
}

};

Then use as...

#include <iostream>

int
main (int argc, char **argv)
{
using char_type = decltype(std::cout)::char_type;

counting_streambuf<char_type> csb;

/*
* Associate the counting_streambuf with std::cout whilst
* retaining a pointer to the original std::streambuf.
*/
auto *oldbuf = std::cout.rdbuf(&csb);
std::cout << "Some text goes here...\n";

/*
* Restore the original std::streambuf.
*/
std::cout.rdbuf(oldbuf);
std::cout << "output length is " << csb.count << " characters\n";
}

Running the above results in...

output length is 23 characters

Edit: The original solution didn't overload overflow. This works on Linux but not on Windows. Thanks go to Peter Dimov from Boost, who found the solution.

Is it allowed to write to a ofstream when it is not opened in c++

The standard behavior is that the first write fails. This sets the std::ofstream::badbit and further writes are silently ignored.

This silent failure could be changed to an exception by setting m_myFile.exceptions(std::ofstream::badbit), but it's off by default.

You can make any stream (even std::cout) discard its output by creating a "dev null" streambuf and then switching your stream to that buffer (via .rdbuf)

Why the constructor of std::ostream is protected?

I'll admit that I don't understand it either. I can't find any
default constructor at all for std::istream, and I would think
you would want one if you want to create a bidirectional stream,
because of the strange way std::ios_base works: the
constructor does not initialize anything, but the derived
class must call std::ios_base::init explicitly in its
constructor. When multiple inheritance is involved (i.e.
bidirectional IO, where the class derives from both
std::istream and std::ostream), I would expect only the most
derived class to call std::ios_base::init. (In
std::iostream, std::ios_base::init will be called twice.)
In fact, before looking it up in the standard, I was about to
answer that the default constructor was protected, because it
didn't call std::ios_base::init, and using it directly, rather
than in a derived class, would result in an uninitialized
stream.

Anyhow, your immediate problem has a simple solution:

std::ostream out( NULL );

Also: the function you need to set up its sink later is the
non-const version of rdbuf(), not copyfmt(). rdbuf() is
used to read and to set the pointer to the streambuf,
copyfmt() copies the formatting flags, but does not touch
the pointer to streambuf.

So you can do things like:

std::ostream out( NULL );
// ...
std::filebuf fileBuffer;
if ( filenameGiven ) {
fileBuffer.open( filename.c_str(), std::ios_base::out );
}
if ( fileIsOpen() ) {
out.rdbuf( &fileBuffer );
} else {
out.rdbuf( std::cout.rdbuf() );
}

(I do this a lot. In fact, I thought that it was the usual
idiom when you didn't know up front whether to output to a file
or to std::cout.)

EDIT:

And yet another correction: the non-const version of rdbuf calls clear(),
so you don't have to. (I knew I'd done this without calling clear(), but
when I saw that init set badbit...)

Anyhow: the summary is: it's usually preferrable to pass a pointer to a valid
streambuf to the constructor of std::ostream, but if you can't, it's
perfectly valid to pass a null pointer, and set a valid pointer later using
rdbuf(). And the answers which say otherwise are simply wrong.

Redirect debug output to null stream instead of std::cerr

There is no real need to be worried about the stream not being good()! Since the output operators don't really do anything wirh a stream in failure mode the different entities being logged are not formatted, i.e., the code does run faster compared to alternative approaches.

Note that you don't really need a second stream to disable output:

  1. Assuming all output operators are well-behaved, you can just set std::ios_base::failbit:

    debugStream().setstate(std::ios_base::failbit);
  2. If there are misbehaved output which write to a stream even if it isn't good() you can just set its stream buffer to null:

    debugStream().rdbuf(nullptr);

If you really want your stream to remain in good() state, you'd install a stream buffer which just consumes characters. Note, however, that you want to give this stream buffer a buffer as having overflow() called for each char is fairly exensive:

struct nullbuf
: std::streambuf {
char buf[256];
int overflow(int c) {
this->setp(this->buf, this->buf + 256);
return std::char_traits<char>::not_eof(c);
}
};
...
nullbuf sbuf;
debugStream().rdbuf(&sbuf);
...
debugStream().rdbuf(0);

It is necessary to reset the stream's stream buffer because the destructor of an std::ostream will flush the stresm buffer (i.e., it calls pubsync()). Doing so on a destroyed stream buffer won't work.

Personally, I would go with setting std::ios_base::failbit.

How to use boost::iostreams::null_sink as std::ostream

Using Standard Library

Just reset the rdbuf:

auto old_buffer = std::cout.rdbuf(nullptr);

Otherwise, just use a stream:

std::ostream nullout(nullptr);
std::ostream& out = verbose? std::cout : nullout;

See it Live On Coliru

#include <iostream>

int main(int argc, char**) {
bool verbose = argc>1;

std::cout << "Running in verbose mode: " << std::boolalpha << verbose << "\n";

std::ostream nullout(nullptr);
std::ostream& out = verbose? std::cout : nullout;

out << "Hello world\n";
}

When run ./test.exe:

Running in verbose mode: false

When run ./test.exe --verbose:

Running in verbose mode: true
Hello world

Using Boost Iostreams

You /can/ of course use Boost IOstreams if you insist:

Note, as per the comments, this is strictly better because the stream will not be in "error" state all the time.

Live On Coliru

#include <iostream>
#include <boost/iostreams/device/null.hpp>
#include <boost/iostreams/stream.hpp>

int main(int argc, char**) {
bool verbose = argc>1;

std::cout << "Running in verbose mode: " << std::boolalpha << verbose << "\n";

boost::iostreams::stream<boost::iostreams::null_sink> nullout { boost::iostreams::null_sink{} };
std::ostream& out = verbose? std::cout : nullout;

out << "Hello world\n";
}


Related Topics



Leave a reply



Submit