捕获和引发 std::cout 刷新事件上的事件
Capturing and raising events on std::cout flush events
我正在尝试编写一个作用域对象来重定向std::cout
的输出,并在刷新底层缓冲区时调用函数。
我的实现大量借鉴了以下 SO 答案:
C++ 在写入流时执行函数
我让它部分工作,但回调函数仅在我显式调用flush
时调用 std::cout
.但是,我希望它在向流写入任何内容时调用回调函数。
注意:我正在编译 aginst MSVC++11。
struct stream_redirect
{
stream_redirect(std::ostream& stream, std::streambuf* rdbuf) :
stream(stream),
rdbuf_old(stream.rdbuf())
{
stream.set_rdbuf(rdbuf);
}
~stream_redirect()
{
stream.set_rdbuf(rdbuf_old);
}
private:
stream_redirect(const stream_redirect&) = delete;
stream_redirect& operator = (const stream_redirect&) = delete;
std::ostream& stream;
std::streambuf* rdbuf_old;
};
struct functionbuf : public std::streambuf
{
typedef std::function<void(std::string)> function_type;
functionbuf(const function_type& function)
: function(function)
{
setp(buffer, buffer + sizeof(buffer) - 1);
}
private:
char buffer[1024];
function_type function;
virtual int_type overflow(int_type c) override
{
if (!traits_type::eq_int_type(c, traits_type::eof()))
{
*this->pptr() = traits_type::to_char_type(c);
pbump(1);
}
return sync() ? traits_type::not_eof(c) : traits_type::eof();
}
virtual int_type sync() override
{
if (pbase() != pptr())
{
function(std::string(pbase(), pptr()));
setp(pbase(), epptr());
}
return 0;
}
};
struct ofunctionstream :
private virtual functionbuf,
public std::ostream
{
ofunctionstream(const function_type& function) :
functionbuf(function),
std::ostream(static_cast<std::streambuf*>(this))
{
setf(std::ios_base::unitbuf);
}
};
现在一个使用示例:
void callback(std::string string)
{
printf("callback(%s)n", string.c_str());
}
int main()
{
ofunctionstream fs(&callback);
stream_redirect sr(std::cout, fs.rdbuf());
printf("sending string to cout...");
std::cout << "hello!";
printf("string sent to cout");
//this is necessary to
printf("flushing cout...");
std::cout.flush();
printf("cout flushed");
}
我得到以下输出:
sending string to cout...
string sent to cout
flushing cout...
callback(hello!)
cout flushed
同样,我希望在调用std::cout << "hello!";
后立即调用该回调函数。 我以为会发生这种情况,因为我正在其构造函数中的ofunctionstream
对象上调用setf(std::ios_base::unitbuf)
(http://en.cppreference.com/w/cpp/io/manip/unitbuf)。
任何帮助将不胜感激!
如果您检查正在使用的回调的工作原理,它会通过子类化std::streambuf
和覆盖overflow()
来工作。这一点很重要。
引用C++标准库的相关部分:
27.6.3.2.5 放置区域 [streambuf.pub.put]
int_type痰(char_type c);
返回:如果输出序列写入位置不可用, 返回溢出(特征::to_int_- 类型(c))。否则,将 c 存储在 输出序列的下一个指针,递增指针,以及 返回特征::to_int_type(c)
std::ostream
,又名格式化输出,使用 sputc() 写入流缓冲区。因此,唯一一次调用overflow()
是在输出缓冲区耗尽时。或明确通过std::flush
.
因此,不幸的是,您的选择有些有限。要么处理当前行为,要么将std::streambuf
子类绑定为根本没有写入缓冲区,以便最终通过sputc()
写入的每个字符都将被戳入overflow()
,并调用您的子类实现。
不幸的是,流操作在每次格式化操作后都不会执行任何显式操作,这可能会被std::streambuf
截获。它们只是通过 sputc()
写入格式化的输出,一次一个字符,以便输出被收集到 streambuf 的写入缓冲区中,该缓冲区仅在已满或显式使用std::flush
时才会被刷新。
所以,这就是它的工作原理。
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- Android NDK传感器向事件队列报告奇怪的间隔
- std::cout.imbue()多重调用
- 从文本文件中读取时钟时间和事件时间并进行处理
- WMI检测进程创建事件-c++
- EvtExportLogneneneba API正在将远程计算机的事件日志保存到远程PC本身.如何将其保存到主机
- 如何在C++中用std::cout正确显示带十六进制的字符串文本
- 为什么在C的循环中使用printf的Rust代码不显示输出,而在C++的循环中显示std::cout
- 为什么我应该在异常处理中使用std::cerr而不是std::cout
- 处理闪烁窗口事件
- C++Builder中的OnClick事件签名存在问题
- 跟踪滚动条上的鼠标事件
- 什么是事件表 (wxWidgets)?
- 如何在 MFCaptureEngine 中获取"Camera removed"事件
- 给定顺序中的事件处理
- 当服务中的事件被触发时,如何将响应从服务发送回客户端?
- 在作为静态成员包含在另一个类中的类的构造函数中使用 cout
- 在 C++/CLI 中将 .NET 事件从一个 DLL 引发到另一个 DLL
- 在 COUT 语句中使用 COUT 调用函数
- 捕获和引发 std::cout 刷新事件上的事件