草庐IT

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

coder 2024-02-22 原文

我正在尝试编写一个作用域对象来重定向 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/

有关c++ - 在 std::cout 刷新事件上捕获和引发事件的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - Capybara-webkit 引发 Capybara::Driver::Webkit::WebkitInvalidResponseError - 2

    我在rspec中收到来自webkit驱动程序的以下消息:Capybara::Driver::Webkit::WebkitInvalidResponseError:UnabletoloadURL:http://127.0.0.1:44923/posts几天前它成功了。问题出在save_page方法上。有什么问题吗? 最佳答案 当我的页面出现错误时,我收到过类似的错误消息。您应该通过在测试模式下启动服务器(railss-etest)并自行访问页面来手动检查情况是否如此。 关于ruby-on-

  3. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  4. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  5. ruby - 如何让Ruby捕获线程中的语法错误 - 2

    我正在尝试使用ruby​​编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?

  6. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  7. ruby-on-rails - 无法在 Rails 助手中捕获 block 的输出 - 2

    我在使用自定义RailsFormBuilder时遇到了问题,从昨天晚上开始我就发疯了。基本上我想对我的构建器方法之一有一个可选block,以便我可以在我的主要content_tag中显示其他内容。:defform_field(method,&block)content_tag(:div,class:'field')doconcatlabel(method,"Label#{method}")concattext_field(method)capture(&block)ifblock_given?endend当我在我的一个Slim模板中调用该方法时,如下所示:=f.form_field:e

  8. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  9. ruby-on-rails - 事件管理员和自定义方法 - 2

    这是我在ActiveAdmin中的自定义页面ActiveAdmin.register_page"Settings"doaction_itemdolink_to('Importprojects','settings/importprojects')endcontentdopara"Text"endcontrollerdodefimportprojectssystem"rakedataspider:import_projects_ninja"para"OK"endendend我想做的是,当我单击“导入项目”按钮时,我想在Controller中执行rake任务。但是我无法访问该方法。可能是什

  10. ruby - 在 ruby​​ 中生成一个进程,捕获 stdout,stderr,获取退出状态 - 2

    我想从ruby​​rake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调

随机推荐