0

我正在尝试使用boost::iostreams 输出过滤器在我流出的任何内容的开头和结尾添加一个字符串。

我下面的代码有效,但只是第一次;第二次,输出似乎在某个地方丢失了,甚至似乎没有调用 write 方法。起初我以为我正在向触发其失败位的流发送一些东西,但流看起来不错。

同样的问题发生在 mac 和 linux 上,最新的boost 版本(1.48)svn trunk,使用 cout 和文件接收器作为设备。

有人真的看过这个作品吗?那是一个错误吗?或者我在我的代码中做错了什么?

#include <iostream>
#include <sstream>

#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/operations.hpp>

using std::cin;
using std::cout;
using std::endl;
using std::streamsize;
using std::string;
using std::stringstream;

class add_string_output_filter
 : public boost::iostreams::multichar_output_filter
{
    public:

    template<typename Sink>
    streamsize write(Sink& sink, const char* s, streamsize n)
    {
        string out_string = string(s);

        // remove trailing '\0' to prevent line break
        if (out_string[out_string.size()-1] == '\0')
            out_string = out_string.substr(0, out_string.size()-1);

        string pre_string("prepended string - ");
        string app_string(" - appended string");

        stringstream sstrm;
        sstrm << pre_string << out_string << app_string << endl;

        // TODO: char* to string, back to char* ?!?
        return boost::iostreams::write(sink,
                                       sstrm.str().c_str(),
                                       sstrm.str().length());
    }
};

int main()
{
    boost::iostreams::filtering_ostream out;

    out.push(add_string_output_filter());
    out.push(cout);

    // string #01 is printed,
    // string #02 gets lost
    out << "string #01" << endl;
    out << "string #02" << endl;
}
4

1 回答 1

0

好吧,您的代码有很多问题,但我不确定为什么没有输出第二个字符串。当我尝试代码时,您 add_string_output_filter::write只被调用一次(使用 "string #01\n");我希望每次刷新缓冲区时都会调用它(所以在 second 之后第二次std::endl)。但即使它被第二次调用,我也不认为输出是你期望或想要的。对于前缀和后缀行,您必须实际查看数据并'\n'正确处理字符。这使用简单的输出过滤器要简单得多:

class PrefixAndSuffixLineOutputFilter : public boost::iostreams::output_filter
{
    bool isAtStartOfLine;
public:
    PrefixAndSuffixLineOutputFilter() : isAtStartOfLine( true ) {}

    template <typename Sink>
    bool
    put( Sink& dest, char ch )
    {
        static std::string const prefix( "prepending string - " );
        static std::string const suffix( " - appended string" );

        bool retval = true;
        if ( isAtStartOfLine )
            retval = boost::iostreams::write( dest, prefix.data(), prefix.size() ) == prefix.size();
        if ( retval && ch == '\n' )
            retval = boost::iostreams::write( dest, suffix.data(), suffix.size() ) == suffix.size();
        if ( retval )
            retval = boost::iostreams::put( dest, ch );
        isAtStartOfLine = ch == '\n';
        return retval;
    }
};

一般来说,这multichar_output_filter是一种优化。如果您阅读教程,最后会说“请注意,write 的实现与将 shell_comments_output_filter::put 的实现放在从 0 到 n 迭代的 for 循环中所得到的非常相似。” 这真的是关键:output_filter先写简单的,如果分析器显示函数调用导致性能问题,切换到 multichar_output_filter. (请注意,您需要相同的状态,因为无论'\n'多字符缓冲区中出现的位置如何,您都必须正确输出前缀和后缀。)

我可能会补充说,isAtStartOfLine状态在输出过滤器中非常频繁。(请注意,您不能简单地prefix在 every 之后 输出'\n',因为这将导致在"prefix"final 之后有一个悬空字符串'\n',并且"prefix"在第一行的开头没有。)我在自己的代码中有一个很好的例子,它在每一行的开头,但 Jonathan Turkanis 没有在他的教程中包含这个特定的示例。

于 2012-02-13T10:15:38.830 回答