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:
The construction has no non-null precondition, and has only this postcondition:
[C++11: 27.7.3.2/2]:
Postcondition:rdbuf() == sb
.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 onrdbuf()
.But note also:
[C++11: 27.7.3.2/1]:
Effects: Constructs an object of classbasic_ostream
, assigning initial values to the base class by callingbasic_ios<charT,traits>::init(sb)
(27.5.5.2).That
init(sb)
call has the effect of settingbadbit
on the stream whensb
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
ifsb
is not a null pointer, otherwise
badbit
. [..]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 callingrdbuf()->sputc(int_type)
. They may use other public members ofbasic_ostream
except that they shall not invoke any virtual members ofrdbuf()
exceptoverflow()
,xsputn()
, andsync()
.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()
istrue
,ok_ == true
otherwise,ok_ == false
.and, for
explicit operator basic_ostream::sentry::bool() const;
:[C++11: 27.7.3.4/5]:
Effects: Returnsok_
.and:
[C++11: 27.7.3.7/1]:
Each unformatted output function begins execution by constructing an object of classsentry
. If this object returnstrue
, while converting to a value of typebool
, 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
. (Instd::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 usingrdbuf()
. 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:
Assuming all output operators are well-behaved, you can just set
std::ios_base::failbit
:debugStream().setstate(std::ios_base::failbit);
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
Using Std::Visit with Variadic Template Struct
Std Linker Error with Apple Llvm 4.1
Sse-Copy, Avx-Copy and Std::Copy Performance
Ensuring C++ Doubles Are 64 Bits
Get Local Ip-Address Using Boost.Asio
C++ Object Instantiation VS Assignment
Vector <Unsigned Char> VS String for Binary Data
Compile Time String Encryption Using Constexpr
Copy a Std::Vector to a Repeated Field from Protobuf with Memcpy
Double to String Without Scientific Notation or Trailing Zeros, Efficiently
Should I Return an Rvalue Reference (By Std::Move'Ing)
Reshaping a 1-D Array to a Multidimensional Array
Cross-Platform Equivalent to Windows Events
Is Shrink_To_Fit the Proper Way of Reducing the Capacity a 'Std::Vector' to Its Size