我看到许多记录器使用
operator<<
来读取日志消息并将其写入文件:
template<typename T>
Logger& Logger::operator<<(Logger& l, const T& s) {
l.logStream << s;
return l;
}
...
Logger log;
log << "Test message " << 123;
我希望在
"Test message"
和 123
写入流后刷新日志。但是,我希望记录器在到达 ;
时刷新流,而不是由用户控制刷新。
我该怎么做?
我想到了两种解决方案,但我发现两者都不可接受:
我可以将新行放在每个日志消息的开头,以便刷新先前的日志,并且在发生崩溃时我们丢失的只是当前日志。
operator<<
可以冲水。但是,由于磁盘上的写入操作数量(磨损),每次调用 <<
时的刷新都会带来很大的性能损失。我希望同花包含整个消息。
我想要“测试消息”<< 123 to be flushed all together, in a single operation.
您可以通过从
log::operator<<
返回一个代理对象来做到这一点,该对象有自己的 proxy::operator<<
,转发到 log::operator<<
,并在其析构函数中刷新。
类似这样的东西(未经测试):
struct ProxyLogger {
Logger& l;
ProxyLogger(Logger& l) : l(l) {}
template <typename T>
ProxyLogger& operator<<(const T& s) {
l << s;
return *this;
}
~ProxyLogger() { l << std::flush; }
};
template<typename T>
ProxyLogger Logger::operator<<(Logger& l, const T& s) {
l.logStream << s;
return l;
}
用法如前:
Logger log;
log << "Test message " << 123;
// ^^ creates the proxy ^^ here it is destroyed
为了进一步阅读,我建议您参考有关 RAII 的文章(资源获取就是初始化)。