повысить iostreams: output_filter работает только один раз - PullRequest
0 голосов
/ 13 февраля 2012

Я пытаюсь использовать boost :: iostreams выходной фильтр , чтобы добавить строку в начало и конец всего, что я выводил.

Мой код ниже работает, но только в первый раз; во второй раз вывод кажется где-то потерянным, а метод записи даже не вызывается. Сначала я подумал, что отправляю что-то в поток, который запускает бит сбоя, но поток кажется хорошим.

Та же проблема возникает в 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;
}

1 Ответ

0 голосов
/ 13 февраля 2012

Ну, с вашим кодом много чего не так, но я не уверен, почему вторая строка не выводится.Когда я пробую код, ваш add_string_output_filter::write вызывается только один раз (с "string #01\n");Я ожидаю, что он будет вызываться каждый раз, когда буфер очищается (так второй раз после второго 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 внутри цикла for с итерацией от 0 до n».действительно ключ: сначала напишите простое output_filter, и если профилировщик покажет, что вызовы функций вызывают проблемы с производительностью, переключитесь на multichar_output_filter.(И обратите внимание, что в нем вам понадобится одно и то же состояние, поскольку вы должны будете правильно вывести префикс и суффикс независимо от того, где '\n' находится в буфере с несколькими символами.)

Я мог бы добавить, чтоisAtStartOfLine состояние очень часто встречается в выходных фильтрах.(Обратите внимание, что вы не можете просто выводить prefix после каждого '\n', так как это приведет к появлению висящей строки "prefix" после последнего '\n', и не будет "prefix" в начале первой строки.) Я имелхороший пример этого в моем собственном коде, который вставлял метку времени в начале каждой строки, но Джонатан Турканис не включил этот конкретный пример в свое руководство.

...