Platform independent /dev/null in c++ [duplicate]

我是研究僧i 提交于 2019-11-28 23:08:29

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

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

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" ;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!