2011-06-12 2 views
1

나는 그 iostreams 패키지를 부스트하고 문서를 조금 더 얇게 찾는 것이 처음이다. 잘만되면 누군가 나를 똑바로 세울 것입니다. 압축 된 스트림을 읽는 동안 잠시 쓴 C# 스트림 코드의 작은 조각을 변환하려고합니다.boost :: iostreams resources를 관리하는 것

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()으로 전화를 걸고 일부 메커니즘 (예 : 콜백)이 필터의 기본 리소스를 정리하는 것이 좋습니다. 소비자가 스트림을 명시 적 릴리스 함수에 전달하도록 요구하는 것은 가능하지만, 기본 데이터 버퍼를 처음부터 다시 얻는 방법에 대해서는 여전히 확실하지 않습니다.

클리너 대체 솔루션도 환영합니다.

나는 표준 : : 벡터 백업 드라이버에 대한 고양이 플러스 플러스로 주석에 압류 느슨하게 해봤 1

업데이트. 그건 내가 한 일이 아니지만, 지금까지 내가 생각해 낸 것입니다. 다음 코드에서, boost :: shared_array 지원 드라이버는 boost 드라이버 예제를 기반으로합니다.

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 (때로는)에서 깊이 깊고 깊숙이 박살납니다. 잘 쓰레기, 나는 범위를 벗어났다. 그리고 물건은 부서졌다, 일부 지방의 것은 deconstructing하고, 모든 것을 골라 내야한다. data은 shared_array에 있으며 in은 힙에 있으며 압축 프로그램은 docs에 따라 생성됩니다.

부스트 생성자 또는 함수 중 하나가 스택의 객체에 대한 참조 (즉, io :: stream 또는 filtering_stream의 푸시)를 가져 오는 중 하나입니까? 그렇다면, 나는 힙에있는 관리되지 않는 오브젝트를 가지고 사각형으로 돌아 간다.

+0

항상 0입니까? 아무 가치도 부여하지 않습니다. –

답변

0

궁극적으로 Boost iostream을 스스로 정리하기 위해 포기해야했습니다. boost :: shared_array를 내부적으로 사용하는 사용자 정의 배열 장치를 만드는 동안 내 데이터 버퍼가 힙에 남아있는 문제를 해결했습니다. boost :: iostreams :: filtering_stream/streambuf는 체인에 푸시 된 객체에 대한 참조를 가져옵니다 이는 스택에서 내 장치에 대한 참조를 캡처한다는 것을 의미합니다 (소스와 동작에서 추측 할 수있는만큼). 나는 힙에 장치를 새로 만들 수 있지만, 그것은 단지 나를 정사각형으로 되 돌린다.

내 다음 솔루션은 스트림의 생성을 boost :: shared_ptr 내부로 반환 할 수있는 간단한 std :: istream 래퍼로 이동하여 마지막 참조가 삭제 될 때 모든 리소스를 정리할 수 있도록합니다.

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

파일이 다른 섹터로 가득 차 있습니다 - 그 중 하나만 압축을 풀고 싶습니다. 파일 핸들이 스트림의 수명보다 오래 지속될 것이라는 보장은 없습니다. –

+0

@jaquadro :'std :: vector'가 지원하는 장치를 쓰고 수동으로 할당 된'char' 배열 대신에이 장치를 사용해볼 수도 있습니다. 그것은 적절한 순간에 버퍼를 릴리스 돌봐야한다. –