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)

Community
  • 1
  • 1
calccrypto
  • 8,583
  • 21
  • 68
  • 99
  • 2
    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. – Codie CodeMonkey Jun 05 '11 at 04:13
  • 1
    What does `"but destroyed if not"` mean? Why don't you write pseudocode to clarify your question? – Nawaz Jun 05 '11 at 04:22
  • 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 terminal – calccrypto Jun 05 '11 at 04:55
  • So basically the ostream equivalent of /dev/null – Chris Eberle Jun 05 '11 at 05:43
  • 1
    why the negative vote and close votes?? – calccrypto Jun 05 '11 at 06:02
  • @calc: My guess, didn't downvote: because the question isn't really clear. As @Nawaz says, what does "but destroyed if not" mean? – Xeo Jun 05 '11 at 06:03
  • @calc: See my answer again, edited it. – Xeo Jun 05 '11 at 06:27
  • 1
    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? – cheshirekow Jun 05 '12 at 13:50

3 Answers3

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
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • 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. – Hugues Nov 19 '14 at 16:47
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

rlduffy
  • 608
  • 4
  • 8
  • ... 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. – Chris Eberle Jun 05 '11 at 05:48
  • thats true. but the user would still have to create the stream in the first place – calccrypto Jun 05 '11 at 06:02
  • and how would i use it? `std::ostream stream = NUL` and `std::ostream stream = std::ostream(NUL)` dont work as parameters – calccrypto Jun 05 '11 at 06:13
  • @calc: If you want a non-portable one, you can try `std::ostream stream("/dev/null")` on Linux / Unix. – Xeo Jun 05 '11 at 06:36
  • 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. – Chris Eberle Jun 05 '11 at 14:06
-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" ;
}
Ali1S232
  • 3,373
  • 2
  • 27
  • 46
  • 3
    -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 ... – Xeo Jun 05 '11 at 06:35
  • it works and compiles using vc++ but seems to have some problems with gcc. – Ali1S232 Jun 05 '11 at 06:44