C ++中平台无关的/dev/null

21

可能重复:
实现一个无操作的std::ostream

C++中有没有流的等效NULL?我想编写一个函数,如果用户想将内部输出到某个地方,则接受流作为参数,但如果不需要,则输出到某个虚假的位置。

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

我希望能够选择执行data()data(std::cout)


2
你正在寻找一种“黑洞”流,可以向其中写入数据但不做任何处理吗?我想你可以自己创建一个,但大多数人在尝试写入之前只需检查流指针是否为NULL即可。 - Codie CodeMonkey
1
“但如果不被销毁”是什么意思?为什么不写伪代码来澄清你的问题? - Nawaz
我不在乎它去哪里,只要它不会出现在用户会检查的任何地方,比如文件或终端。 - calccrypto
1
为什么会有负面评分和关闭投票? - calccrypto
1
这个问题被关闭为完全重复,但没有给出它是重复的哪个链接。我们能否得到另一个问题的链接? - cheshirekow
显示剩余3条评论
3个回答

35

编辑:取自 @Johannes Schaub - litb 的邮件 这里,稍作修改:

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

使用这些:

void data(std::ostream& stream = cnull){
  // whatever...
}
现在,这看起来很酷,但接下来的方法更加简短且奏效,因为如果向 ostream 的构造函数提供空指针,它会自动设置 badbit 并静默地忽略任何写入:
// in .h
extern std::ostream cnull;
extern std::wostream wcnull;

// in .cpp
std::ostream cnull(0);
std::wostream wcnull(0);
标准保证这个工作,从27.6.2.2 [lib.ostream.cons] p1开始描述了带有指向streambuf的指针的ostream构造函数的内容:

效果:构造一个basic_ostream类的对象,通过调用basic_ios<charT,traits>::init(sb)为基类分配初始值。

来自basic_ios的相关函数27.4.4.1 [lib.basic.ios.cons] p3

void init(basic_streambuf<charT,traits>* sb);
后置条件:此函数的后置条件在表89中指示:

表89中的重要行:

rdstate() -- 如果sb不是空指针,则为goodbit,否则为badbit。

如果设置了badbit,则在27.6.2.6 [lib.ostream.unformatted]下描述了会发生什么:

每个未格式化的输出函数都以构造一个sentry类对象开始执行。如果该对象在转换为bool类型时返回true,则努力生成所请求的输出。

这意味着,如果sentry为false,则不会生成输出。以下是sentry如何转换为bool,取自27.6.2.3 [lib.ostream::sentry] p3 & p5

3) 如果完成任何准备工作后,os.good()true,则ok_ == true,否则ok_ == false

5) operator bool();
效果:返回ok_。

ok_ostream::sentry的一个类型为bool的成员。)
请注意,这些引用仍然存在于C++11中,只是位置不同。按照此答案中出现的顺序:
  • 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]
  • 表89 => 表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

感谢您的好回答。这两种方案的os.good()有区别吗?使用std::ostream os(nullptr)assert(os)将会失败,而使用std::ostream os(&nullobj)assert(os)则不会?我只是猜测。 - Hugues

1

Linux文件/dev/null就像你正在寻找的黑洞一样。在Windows中有一个叫做NUL:的设备。我从未尝试打开过那个文件,但我曾经在命令行中使用过它。


你可以不用打开这些特殊文件就能做同样的事情。从技术上讲,你只需要在你的 << 重载中接受参数,然后简单地不对它们进行任何操作即可。 - Chris Eberle
这是正确的。但用户仍然需要首先创建流。 - calccrypto
std::ostream stream = NULstd::ostream stream = std::ostream(NUL) 不适用于参数。请问我该如何使用它? - calccrypto
如果你想要一个非便携式的,你可以在Linux / Unix上尝试std::ostream stream("/dev/null") - Xeo
不不,重点是你要自己创建一个ostream(称为blackhole或其他名称),当写入时它会忽略所有数据。这与空指针无关。 - Chris Eberle

-1

你可以尝试使用ostream(NULL,false),第一个输入是目标输出,我不知道第二个输入确切的含义,但在跟踪代码后,似乎只是因为ostream没有写入的位置,调用operator <<被ostream忽略了。我的意思是,在第一次调用中,状态会变为bad,之后由于流的状态,始终会忽略输入数据,因此你可以使用以下代码:

void data(std::ostream & stream = ostream(NULL,false)){
    stream << "DATA" ;
}

3
这不起作用。临时变量只能绑定到const T&引用,但无法将常量流写入。我认为MSVC允许这种方式作为扩展,但是... - Xeo
它在使用VC++编译时可以工作和编译,但似乎在使用GCC时存在一些问题。 - Ali1S232

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接