gpt4 book ai didi

c++ - 在 std::cout 刷新事件上捕获和引发事件

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:01:31 29 4
gpt4 key购买 nike

我正在尝试编写一个作用域对象来重定向 std::cout 的输出并在刷新底层缓冲区时调用函数。

我的实现大量借鉴了以下 SO 答案:

c++ execute function any time a stream is written to

我让它部分工作,但只有在我明确调用 flush 时才会调用回调函数在 std::cout .但是,我希望它在任何内容 写入流时调用回调函数。

注意:我正在编译 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!";叫做。我假设这会发生,因为我调用 setf(std::ios_base::unitbuf) ( http://en.cppreference.com/w/cpp/io/manip/unitbuf ) 在 ofunctionstream 上构造函数中的对象。

非常感谢任何帮助!

最佳答案

如果您检查您正在使用的回调是如何工作的,它是通过子类化 std::streambuf 来工作的并通过覆盖 overflow() .这点很重要。

引用C++标准库的相关部分:

27.6.3.2.5 Put area [streambuf.pub.put]

int_type sputc(char_type c);

Returns: If the output sequence write position is not available, returns overflow(traits::to_int_- type(c)). Otherwise, stores c at the next pointer for the output sequence, increments the pointer, and returns traits::to_int_type(c)

std::ostream ,也就是格式化输出,使用 sputc() 写入流缓冲区。所以,唯一一次overflow()被调用是在输出缓冲区耗尽时。或者明确地通过 std::flush .

因此,不幸的是,您的选择有些有限。要么处理当前行为,要么陪审团 std::streambuf子类根本没有写入缓冲区,因此每个字符最终都会通过sputc()写入会被踢到overflow() ,并调用您的子类实现。

不幸的是,流操作不会在每次格式化操作后执行任何显式操作,这可以被 std::streambuf 拦截.他们只是写格式化输出,一次一个字符,通过 sputc() , 这样输出就被收集到 streambuf 的写入缓冲区中,只有当缓冲区已满或 std::flush 时才会被刷新。被明确使用。

所以,这就是它的工作原理。

关于c++ - 在 std::cout 刷新事件上捕获和引发事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30970385/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com