一个解决方案是将所有写入cerr的内容复制到一个文件中。
这是帮助类:
class CTee {
public:
CTee(ostream &s1, ostream &s2) : m_s1(s1), m_s1OrigBuf(s1.rdbuf()), m_teebuf(s1.rdbuf(), s2.rdbuf()) { s1.rdbuf(&m_teebuf); }
~CTee() { m_s1.rdbuf(m_s1OrigBuf); }
private:
CTee &operator =(CTee &rhs);
class CTeeBuf : public streambuf {
public:
CTeeBuf(streambuf* sb1, streambuf* sb2) : m_sb1(sb1), m_sb2(sb2) {}
protected:
virtual int_type overflow(int_type c) {
if(streambuf::traits_type::eq_int_type(c, streambuf::traits_type::eof()))
return c;
else {
m_sb1->sputc((streambuf::char_type)c);
return m_sb2->sputc((streambuf::char_type)c);
}
}
virtual int sync() {
m_sb1->pubsync();
return m_sb2->pubsync();
}
streambuf *m_sb1, *m_sb2;
};
ostream &m_s1;
streambuf * const m_s1OrigBuf;
CTeeBuf m_teebuf;
};
CTee需要一个
ostream
作为复制源和一个
ostream
作为复制目标。它获取将要被复制的
ostream
并用CTeeBuf(请参阅CTee ctor)替换其
rdbuf
,即被写入到的
streambuf
。CTeeBuf将写入其中的
char
转发到两个
ostream
的
streambuf
中(请参阅CTeeBuf::overflow和CTeeBuf::sync)。CTee dtor将更改后的
streambuf
恢复为其原始值。
使用方法如下:
char logfilename[] = "myfile.log";
ofstream logfile(logfilename, ios_base::out | ios_base::app);
CTee tee(cerr, logfile);
从现在开始,所有写入 cerr 的内容都会被复制到日志文件中(在 tee 的生命周期内)。因此,这条消息将被写入 cerr,也会被写入日志文件:
cerr << "error occured: ..." << endl;
除了日志文件之外,还可以将内容写入其他的输出流。如果您不想将内容复制到另一个ostream
而是想要复制到其他地方,请将CTeeBuf::overflow替换为在任何您想要记录的位置实现的函数。
另请参阅http://www.cs.technion.ac.il/~imaman/programs/teestream.html和http://wordaligned.org/articles/cpp-streambufs。
cout
后面的.rdbuf
。 - MSalters