2011-06-12 6 views
1

私はブーストとそのiostreamsパッケージを新しくして、ドキュメントを少し薄くしています。私は、私は圧縮されたストリームを読み込むために書き込んだC#ストリームコードの小さな部分を変換しようとしています。boost :: iostreamsはリソースを管理しています

byte[] data = new byte[length - 1]; 
file.Read(data, 0, data.Length); 

Stream ret = new ZlibStream(new MemoryStream(data), CompressionMode.Decompress, true); 
return ret; 

ファイルの一部からのデータは、zlibデコンプレッサに供給するメモリバッファに読み込まれます。ストリームの消費者は時間がたつにつれてそれを取り除き、終了するとClose()と呼ばれ、ガベージコレクタと組み合わされてすべてのリソースがクリーンアップされます。 注::重要な違​​いは、ファイル全体を解凍しようとしていないことです。ファイルは既に内部の場所にシーク​​されており、ファイルのフルサイズに比べて長さが短くなっています。

私はBoostのC++コードでこれに匹敵する最高のものを考え出しています。これまでのところ、私はこの道徳的上記(未テスト)に相当します:私は、ストリームの削除を気にすることから、消費者を救うshared_ptrに包まれfiltering_streamを返すことができると仮定し

char * data = new char[length - 1]; 
_file.read(data, length - 1); 

io::stream_buffer<io::basic_array_source<char> > buffer(data, length - 1); 

io::filtering_stream<io::input> * in = new io::filtering_stream<io::input>;   
in->push(io::zlib_decompressor()); 
in->push(buffer); 

return in; 

を、私も持っていますそのデータバッファーはそこに新しいものがあります。理想的には、消費者がストリーム上でclose()と呼ぶようにしたいと思っています。そして、ある種のメカニズム(コールバックなど)がフィルタの基礎となるリソースをクリーンアップします。消費者がストリームを明示的なリリース関数に渡すように要求することも許容されますが、最初の場所で元のデータバッファを戻す方法はまだ完全にはわかりません。

クリーナーの代替ソリューションも歓迎します。

私がのstd ::ベクトル担保ドライバに関するキャットプラスプラスすることによってコメントに押収緩く試してみた1

更新。それは私がやったことではありませんが、これはこれまで私が思いついたことです。次のコードでは、boostドライバの例に基づいて、boost :: shared_arrayでバックアップされたドライバがあります。

namespace io = boost::iostreams; 

class shared_array_source 
{ 
public: 

    typedef char   char_type; 
    typedef io::source_tag category; 

    shared_array_source (boost::shared_array<char> s, std::streamsize n) 
     : _data(s), _pos(0), _len(n) 
    { } 

    std::streamsize read (char * s, std::streamsize n) 
    { 
     std::streamsize amt = _len - _pos; 
     std::streamsize result = (std::min)(amt, n); 

     if (result != 0) { 
      std::copy(_data.get() + _pos, _data.get() + _pos + result, s); 
      return result; 
     } 
     else { 
      return -1; 
     } 
    } 

private: 
    boost::shared_array<char> _data; 
    std::streamsize _pos; 
    std::streamsize _len; 
}; 

その後、私はストリーム

io::filtering_istream * GetInputStream (...) 
{ 
    // ... manipulations on _file, etc. 

    boost::shared_array<char> data(new char[length - 1]); 
    _file.read(data.get(), length - 1); 

    shared_array_source src(data, length - 1); 
    io::stream<shared_array_source> buffer(src); 

    io::filtering_istream * in = new io::filtering_istream; 
    in->push(io::zlib_decompressor()); 
    in->push(buffer); 

    // Exhibit A 
    // uint32_t ui; 
    // rstr->read((char *)&ui, 4); 

    return in; 
} 

そして、テストプログラムの私の主な機能でを返す私の機能を持っている:

int main() { 
    boost::iostreams::filtering_istream * istr = GetInputStream(); 

    // Exhibit B 
    uint32_t ui; 
    rstr->read((char *)&ui, 4); 

    return 0; 
} 

は私がポインタを返すてるという事実を無視それは決して解放されません - 私はこれを可能な限りシンプルに保っています。これを実行するとどうなりますか? Exhibit Aのコードのコメントを外すと、uiに適切な情報が得られます。しかし、私がExhibit Bを打ったとき、私はBoost(時には)で深く、深く、深く墜落します。うんざり、私は範囲外に出て、物事が壊れた、いくつかのローカルは、すべてを解体し、混乱させる必要があります。 dataはshared_arrayにあり、inはヒープ上にあり、コンプレッサーはドキュメントに従って構築されています。

ブーストコンストラクタまたは関数の1つは、スタック上のオブジェクトへの参照(つまり、io :: streamまたはfiltering_streamのプッシュ)を取得していますか?その場合、ヒープ上の管理されていないオブジェクトを持つ正方形に戻っています。

+0

常にゼロに等しいか? これは決して価値がありません。 –

答えて

0

最終的に私はブーストiostreamsを自分自身の後でクリーンアップしようとすることをあきらめなければならなかった。 boost :: shared_arrayを内部的に使用しているカスタム配列デバイスを作成しているうちに、私のデータバッファがヒープ上に残っているという問題を解決したので、boost :: iostreams :: filtering_stream/streambufはチェーンにプッシュされたオブジェクトへの参照を取るこれはスタック上のデバイスへの参照をキャプチャしていたことを意味します(ソースと動作から推測できる限り)。私はヒープ上のデバイスを新しくできましたが、それは私を正方形に戻すだけです。

次の解決策は、ストリームの作成を細かいstd :: istreamラッパーに移動します。このラッパーは、boost :: shared_ptrの中に返すことができ、最後の参照が破棄されたときにすべてのリソースをクリーンアップできます。

template <class Compressor> 
class CompressedIStream : public std::basic_istream<char, std::char_traits<char> > 
{ 
public: 
    CompressedIStream (std::istream& source, std::streamsize count) 
     : _data(new char[count]), _buffer(_data, count), std::basic_istream<char, std::char_traits<char> >(&_filter) 
    { 
     source.read(_data, count); 

     _filter.push(Compressor()); 
     _filter.push(_buffer); 
    } 

    virtual ~CompressedIStream() 
    { 
     delete[] _data; 
    } 

private: 
    char * _data; 
    io::stream_buffer<io::basic_array_source<char> > _buffer; 
    io::filtering_istreambuf _filter; 
}; 

boost::shared_ptr<std::istream> GetInputStream (...) 
{ 
    // ... manipulations on _file, etc. 

    typedef CompressedIStream<io::zlib_decompressor> StreamType; 
    return boost::shared_ptr<StreamType>(new StreamType(_file, length - 1)); 
} 
1

本当にヒープには何も割り当てないでください。 filtering_streamはオンザフライで解凍できるので、バッファを交換するか、ファイルの内容を最初に読み取る必要はありません。あなた本当には、[はい、あなたはスマートポインタ(でそれをラップする必要がありますが、再び、ファイルデータを読んでいない、ヒープ上に割り当てる必要がある場合は

io::filtering_stream stream; 
stream.push(io::zlib_decompressor()); 
stream.push(_file); 

:コードはより次のようになります。最初に、あなたはそのバッファのリークを危険にさらしています。大きなファイルを読むことは、非常に効率の悪いことではありません)。

+0

ファイルはさまざまなセクタでいっぱいです。そのうちの1つだけを解凍したいだけです。ファイルハンドルがストリームの存続期間を超えて持続するという保証はありません。 –

+0

@jaquadro: 'std :: vector'がサポートするデバイスを書き、手動で割り当てられた' char'配列の代わりにそれを使うこともできます。それは適切な瞬間にバッファを解放するのを世話する必要があります。 –

関連する問題