すぐにフィルタ処理を終えたいときはboost::iostreams::closeを使う

filtering_ostream::flushを呼び出すことで処理が完了すると思っていたのですが、そうでない場合がありました。

#include <iostream>
#include <vector>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/copy.hpp>

int main(){
    namespace io = boost::iostreams;
    typedef std::vector<char> Bytes;

    Bytes gzip_data;
    io::filtering_ostream out;
    out.push(io::gzip_compressor());
    out.push(io::back_inserter(gzip_data));
    out << "Good morning, world!";
    out.flush();
    
    io::filtering_istream in;
    in.push(io::gzip_decompressor());
    in.push(boost::make_iterator_range(gzip_data));
    std::string deco_str;
    try{
        io::copy(in, io::back_inserter(deco_str));
    }
    catch(const std::exception& e){
        std::cout << "Exception: " << e.what() << std::endl;
    }

    std::cout << deco_str << std::endl;

    return 0;
}

Output:

Exception: gzip error


さて、gzip errorです。展開ができず発生しました。
これは圧縮とコンテナへの書き込みの処理が完了していないうちに、入力処理が行われたためです。

boost::iostreams::closeを使えばOKです。

Bytes gzip_data;
io::filtering_ostream out;
out.push(io::gzip_compressor());
out.push(io::back_inserter(gzip_data));
out << "Good morning, world!";
io::close(out); //boost::iostreams::closeを使う

これでようやくfiltering_ostreamの処理が完了します。


gzip圧縮Filterは、ヘッダをSinkに書き出す、圧縮したデータをSinkに書き出す、と処理を2回に分けて行っています。
flushした後のgzip_data変数には10バイト、ヘッダ部しかありません。
closeは、すべての処理を完了させてストリームを閉じます。
flushは、Sinkまでの処理が1回行われたら終わりなようです。