Platform independent /dev/null in c++ [duplicate]
Asked Answered
L

3

21

Possible Duplicate:
Implementing a no-op std::ostream

Is there any stream equivalent of NULL in c++? I want to write a function that takes in a stream if the user wants to have the internal outputted to somewhere, but if not, the output goes into some fake place

void data(std::stream & stream = fake_stream){
    stream << "DATA" ;
}

i want to be able to chose to do data() or data(std::cout)

Lessielessing answered 5/6, 2011 at 4:8 Comment(8)
You're looking for some kind of "black hole" stream that you can write too but which does nothing with the data? You could derive one I suppose, but most people would just check that the stream pointer isn't NULL before attempting to write to it.Searching
What does "but destroyed if not" mean? Why don't you write pseudocode to clarify your question?Bedwell
as in: i dont care where it goes, as long as it doenst show up any where a user would check, like a file, or the terminalLessielessing
So basically the ostream equivalent of /dev/nullHedger
why the negative vote and close votes??Lessielessing
@calc: My guess, didn't downvote: because the question isn't really clear. As @Nawaz says, what does "but destroyed if not" mean?Photothermic
@calc: See my answer again, edited it.Photothermic
This question is closed as exact duplicate but no link is given to what it is a duplicate of. Can we get a link to the other question?Trio
P
35

Edit: Taken from @Johannes Schaub - litb's mail here with slight modifications:

template<typename Ch, typename Traits = std::char_traits<Ch> >
struct basic_nullbuf : std::basic_streambuf<Ch, Traits> {
     typedef std::basic_streambuf<Ch, Traits> base_type;
     typedef typename base_type::int_type int_type;
     typedef typename base_type::traits_type traits_type;

     virtual int_type overflow(int_type c) {
         return traits_type::not_eof(c);
     }
};

// convenient typedefs
typedef basic_nullbuf<char> nullbuf;
typedef basic_nullbuf<wchar_t> wnullbuf;

// buffers and streams
// in some .h
extern std::ostream cnull;
extern std::wostream wcnull;

// in a concrete .cpp
nullbuf null_obj;
wnullbuf wnull_obj;
std::ostream cnull(&null_obj);
std::wostream wcnull(&wnull_obj);

Use those:

void data(std::ostream& stream = cnull){
  // whatever...
}

Now, this looks cool and all, but the following is way shorter and works, because if a null pointer is provided to the constructor of ostream, it automatically sets the badbit and silently ignores any writes:

// in .h
extern std::ostream cnull;
extern std::wostream wcnull;

// in .cpp
std::ostream cnull(0);
std::wostream wcnull(0);

The standard guarantees this works, beginning from 27.6.2.2 [lib.ostream.cons] p1 which describes the constructor of ostream that takes a pointer to a streambuf:

Effects: Constructs an object of class basic_ostream, assigning initial values to the base class by calling basic_ios<charT,traits>::init(sb).

The relevant function from basic_ios, 27.4.4.1 [lib.basic.ios.cons] p3:

void init(basic_streambuf<charT,traits>* sb);
Postconditions: The postconditions of this function are indicated in Table 89:

The important row from Table 89:

rdstate() -- goodbit if sb is not a null pointer, otherwise badbit.

What happens if the badbit is set is described under 27.6.2.6 [lib.ostream.unformatted]:

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.

This implies that, in case the sentry is false, it does not. Here is how the sentry converts to bool, taken from 27.6.2.3 [lib.ostream::sentry] p3 & p5:

3) If, after any preparation is completed, os.good() is true, ok_ == true otherwise, ok_ == false.

5) operator bool();
Effects: Returns ok_.

(ok_ is a member of ostream::sentry of type bool.)


Note that these quotes are still present in C++11, just in different places. In order of appearance in this answer:

  • 27.6.2.2 [lib.ostream.cons] p1 => 27.7.3.2 [ostream.cons] p1
  • 27.4.4.1 [lib.basic.ios.cons] p3 => 27.5.5.2 [basic.ios.cons]
  • Table 89 => Table 128
  • 27.6.2.6 [lib.ostream.unformatted] => 27.7.3.7 [ostream.unformatted] p1
  • 27.6.2.3 [lib.ostream::sentry] p3 & p5 => 27.7.3.4 [ostream::sentry] p4 & p5
Photothermic answered 5/6, 2011 at 4:20 Comment(1)
Thanks for the nice answer. Is there a difference in os.good() for the two schemes? With std::ostream os(nullptr), assert(os) will fail whereas with std::ostream os(&nullobj), assert(os) will not? I'm just guessing.Beaulahbeaulieu
Z
1

Linux file /dev/null is a black hole like you're looking for. In Windows there's a device called NUL:. I've never tried to open that file, but I've used it from the command line

Zasuwa answered 5/6, 2011 at 5:35 Comment(5)
... you could do the same thing without opening these special files. Technically all you need to do is accept arguments in your << overload, and then simply not do anything with them.Hedger
thats true. but the user would still have to create the stream in the first placeLessielessing
and how would i use it? std::ostream stream = NUL and std::ostream stream = std::ostream(NUL) dont work as parametersLessielessing
@calc: If you want a non-portable one, you can try std::ostream stream("/dev/null") on Linux / Unix.Photothermic
No no, the whole point is that you make your OWN ostream (called blackhole or something), which when written to simply ignores all data. This has nothing to do with a null pointer.Hedger
P
-1

you can try ostream(NULL,false), the first input is target output and I don't know what the second input exaclty mean but after tracing code it seems just because ostream has no place to write to, calling operator << is just ignored by ostream. I mean in the first call state changes to bad and after that it's always ignoring input data because of stream state ,so you can use the following code :

void data(std::ostream & stream = ostream(NULL,false)){
    stream << "DATA" ;
}
Pauwles answered 5/6, 2011 at 6:28 Comment(2)
-1, this won't work. A temporary may only bind to a const T& reference, but a constant stream cannot be written to. I think MSVC allows this as an extension, but ...Photothermic
it works and compiles using vc++ but seems to have some problems with gcc.Pauwles

© 2022 - 2024 — McMap. All rights reserved.