0

boost::iostreams 出力フィルターを使用して、ストリーム出力するものの最初と最後に文字列を追加しようとしています。

以下のコードは機能しますが、初回のみです。2 回目は、出力がどこかで失われたように見え、write メソッドが呼び出されていないようです。最初は、失敗ビットをトリガーする何かをストリームに送信していると思いましたが、ストリームは問題ないようです。

同じ問題は、最新のブースト リリース (1.48)svn トランクを使用し、デバイスとして cout とファイル シンクを使用するmac と linux でも発生します。

この作品を実際に見た人はいますか?それはバグですか?または、コードで何か間違ったことをしていますか?

#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

コードには多くの問題がありますが、2番目の文字列が出力されない理由はわかりません。私がコードを試してみると、あなた add_string_output_filter::writeは一度だけ呼び出されます(with "string #01\n"); バッファがフラッシュされるたびに呼び出されると思います(つまり、2回目以降に2回目std::endl)。しかし、2回目に呼び出されたとしても、出力が期待または期待どおりではないと思います。行の接頭辞と接尾辞については、実際にデータを確認し、'\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(すべての後に 単純に出力することはできないことに注意してください。これは、最後の後に'\n'ぶら下がっている文字列になり、最初の行の先頭にはないためです。)これの良い例が自分のコードにあり、タイムスタンプをに挿入しました。各行の先頭ですが、JonathanTurkanisはこの特定の例をチュートリアルに含めていません。"prefix"'\n'"prefix"

于 2012-02-13T10:15:38.830 に答える