【问题标题】:Redirect debug output to null stream instead of std::cerr将调试输出重定向到空流而不是 std::cerr
【发布时间】:2013-10-05 16:47:35
【问题描述】:

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

#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;
}

当你运行这个程序时,你会注意到字符串“bar”被正确地发送到了空流。但是,我注意到断言失败了。这是我应该关心的事情吗?或者这只是库开发人员选择的方法的一个略显丑陋的细节?

如果您愿意,欢迎提出更好的替代方案。一些限制:

  • 该库是跨平台的,所以我认为使用打开 /dev/null 不是一个有效的解决方案,因为它不适用于 Windows
  • 该库使用标准 C++,因此任何替代解决方案都不应使用特定于编译器的东西

【问题讨论】:

    标签: c++ cross-platform iostream


    【解决方案1】:

    没有必要担心流不是good()!由于在失败模式下输出操作符实际上并没有对流执行任何操作,因此记录的不同实体没有被格式化,即,与替代方法相比,代码运行得更快。

    请注意,您实际上并不需要第二个流来禁用输出:

    1. 假设所有输出运算符都表现良好,您可以设置std::ios_base::failbit

      debugStream().setstate(std::ios_base::failbit);
      
    2. 如果存在写入流的异常输出,即使它不是good(),您也可以将其流缓冲区设置为空:

      debugStream().rdbuf(nullptr);

    如果您真的希望您的流保持在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;
    debugStream().rdbuf(&sbuf);
    ...
    debugStream().rdbuf(0);
    

    有必要重置流的流缓冲区,因为std::ostream 的析构函数将刷新压力缓冲区(即,它调用pubsync())。对已破坏的流缓冲区这样做是行不通的。

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

    【讨论】:

      【解决方案2】:

      this answer 中,您可以找到一个通用助手来将任何流重定向到任何其他流:

      class stream_redirector {
      public:
          stream_redirector(std::ios& stream, std::streambuf* newBuf) :
              savedBuf_(stream.rdbuf()), stream_(stream)
          {
              stream_.rdbuf(newBuf);
          }
      
          ~stream_redirector() {
              stream_.rdbuf(savedBuf_);
          }
      
      private:
          std::streambuf* savedBuf_;
          std::ios& stream_;
      };
      

      现在你只需要一个来自this answer 的无操作流,它会丢弃任何东西:

      template <class cT, class traits = std::char_traits<cT> >
      class basic_nullbuf: public std::basic_streambuf<cT, traits> {
          typename traits::int_type overflow(typename traits::int_type c)
          {
              return traits::not_eof(c); // indicate success
          }
      };
      
      template <class cT, class traits = std::char_traits<cT> >
      class basic_onullstream: public std::basic_ostream<cT, traits> {
      public:
          basic_onullstream():
          std::basic_ios<cT, traits>(&m_sbuf),
          std::basic_ostream<cT, traits>(&m_sbuf)
          {
              // note: the original code is missing the required this->
              this->init(&m_sbuf);
          }
      
      private:
          basic_nullbuf<cT, traits> m_sbuf;
      };
      
      typedef basic_onullstream<char> onullstream;
      typedef basic_onullstream<wchar_t> wonullstream;
      

      你很高兴:

      int main(int argc, char** argv)
      {
          std::cerr << "foo" << std::endl;
          {
              onullstream nos;
              stream_redirector sr( std::cerr, nos.rdbuf() );
              std::cerr << "bar" << std::endl;
          }
          std::cerr << "baz" << std::endl;
      }
      

      最后是live example,以防你想玩它。这种方法还有一个额外的好处是您(和您的同事)仍然可以在代码中使用std::cerr,并且您可以随意将其关闭再打开:)

      【讨论】:

      • 我不知道 coliru.stacked-crooked.com。邪恶!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多