我正在使用的软件库将大量调试输出写入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上运行答案 0 :(得分:4)
没有必要担心流不是good()
!由于输出操作员在故障模式下没有真正做任何事情,因此记录的不同实体没有被格式化,即,与其他方法相比,代码确实运行得更快。
请注意,您确实不需要第二个流来禁用输出:
假设所有输出操作符都表现良好,您只需设置std::ios_base::failbit
:
debugStream().setstate(std::ios_base::failbit);
如果有错误的输出写入流,即使它不是good()
,你只需将其流缓冲区设置为null:
debugStream()rdbuf(nullptr);
如果您确实希望您的流保持good()
状态,则需要安装一个仅消耗字符的流缓冲区。但请注意,您希望为此流缓冲区提供缓冲区,因为每个overflow()
调用char
是相当冒犯的:
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
的析构函数将刷新stresm缓冲区(即,它调用pubsync()
)。在已销毁的流缓冲区上执行此操作将无效。
就个人而言,我会设置std::ios_base::failbit
。
答案 1 :(得分:3)
在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
,您可以随意将其关闭再打开:)