将调试输出重定向到null流,而不是std :: cerr [英] Redirect debug output to null stream instead of std::cerr

查看:1161
本文介绍了将调试输出重定向到null流,而不是std :: cerr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用的软件库向 std :: cerr 中写入了大量调试输出,但是如果我告诉它将输出重定向到一个null流安静。这是一个简化的 main.cpp ,显示代码如何尝试实现这一点:

  #include< iostream> 
#include< fstream>
#include< cassert>

//调试输出的流发送到。默认情况下
//这指向std :: cerr。
std :: ostream * debugStream(& std :: cerr);

//在整个库的代码库中,这个函数被调用
//来获取调试输出应该发送到的流。
std :: ostream& DebugStream()
{
return * debugStream;
}

//空流。此文件流将永远不会打开,并将
//作为DebugStream()的空流。
std :: ofstream nullStream;

//将调试输出重定向到null流
void BeQuiet()
{
debugStream =& nullStream;
}

int main(int argc,char ** argv)
{
DebugStream()< foo< std :: endl;
BeQuiet();
DebugStream()<< bar< std :: endl;
assert(debugStream-> good());

return 0;
}

运行此程序时,您会注意到字符串bar正确发送到零流。然而,我注意到断言失败。这是我应该关心的吗?或者,这只是图书馆开发人员选择的方法的一个略微丑陋的细节?



如果你喜欢它,欢迎提出更好的替代方案。一些约束:




  • 库是跨平台的,所以我想使用打开 / dev / null 不是有效的解决方案,因为它不能在Windows上运行

  • 该库使用标准C ++,所以任何替代解决方案不应使用编译器特定的东西


解决方案

没有真正需要担心的流不是 good / code>!由于输出运算符在失败模式下并不真正做任何流,所以不同的实体不被格式化,即,与其他方法相比,代码运行得更快。



注意,你不需要第二个流来禁用输出:


  1. 假设所有的输出操作符都是良好的,您只需设置 std :: ios_base :: failbit

      debugStream()。setstate(std :: ios_base :: failbit); 


  2. 如果有错误的输出写入流,即使不是 good()你可以将它的流缓冲区设置为null:



    debugStream()。rdbuf(nullptr) p>

如果您确实希望将流保留在 good()状态,您将安装一个仅消耗字符的流缓冲区。注意,你想给这个流缓冲区一个缓冲区,因为每个 char 调用 overflow()相当冒险:

  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;
debuggingStream()。rdbuf(& sbuf);
...
DebugStream()。rdbuf(0);

有必要重置流的流缓冲区,因为 std的析构函数:: ostream 将刷新stresm缓冲区(即,它调用 pubsync())。



个人而言,我会设置 std :: ios_base :: failbit


A software library that I am working with writes a lot of debug output to std::cerr, but redirects that output to a null stream if I tell it to be quiet. This is a simplified main.cpp that shows how the code tries to achieve this:

#include <iostream>
#include <fstream>
#include <cassert>

// The stream that debug output is sent to. By default
// this points to std::cerr.
std::ostream* debugStream(&std::cerr);

// Throughout the library's codebase this function is called
// to get the stream that debug output should be sent to.
std::ostream& DebugStream()
{
    return *debugStream;
}

// Null stream. This file stream will never be opened and acts
// as a null stream for DebugStream().
std::ofstream nullStream;

// Redirects debug output to the null stream
void BeQuiet()
{
    debugStream = &nullStream;
}

int main(int argc, char** argv)
{
  DebugStream() << "foo" << std::endl;
  BeQuiet();
  DebugStream() << "bar" << std::endl;
  assert(debugStream->good());

  return 0;
}

When you run this program, you will notice that the string "bar" is correctly sent to the null stream. However, I noticed that the assertion fails. Is this something that I should be concerned about? Or is this just a slightly ugly detail of the approach chosen by the library developers?

If you feel like it, suggestions for better alternatives are welcome. Some constraints:

  • The library is cross-platform, so I think using opening /dev/null is not a valid solution as it would not work on Windows
  • The library uses standard C++, so any alternative solutions should not use compiler-specific stuff

解决方案

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:

  1. Assuming all output operators are well-behaved, you can just set std::ios_base::failbit:

    debugStream().setstate(std::ios_base::failbit);
    

  2. 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.

这篇关于将调试输出重定向到null流,而不是std :: cerr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆