C++11 boost::iostreams::filtering_stream delete
У меня есть данные, которые я хочу отформатировать и вывести, либо в необработанном текстовом файле, либо в сжатом текстовом файле.gz.
Таким образом, я хотел сделать что-то вроде этого:
shared_ptr<ofstream> file = make_shared<ofstream>(filename.c_str());
shared_ptr<ostream> stream;
if (compressed) {
stream = getCompressedStream(*file);
} else {
stream = std::move(file);
}
for (auto c = data.begin(); c != data.end(); ++c) {
*stream << **c << "\t" << (*c)->getThing() << endl;
}
С getCompressedStream функция, которая расшифровывает поток и возвращает новый незашифрованный поток:
std::unique_ptr<std::ostream> getCompressedStream(std::ofstream& file)
{
typedef io::filtering_ostream filter;
std::unique_ptr<filter> out = std::unique_ptr<filter> (new filter());
out->push(io::gzip_compressor());
out->push(file);
return std::move(out);
}
Поэтому я хотел, чтобы getCompressedStream абстрагировал вызовы для повышения lib, чтобы в моей основной программе я использовал только потоки std.
Это не работает: файл.gz поврежден / не читается.
Согласно этому потоку вывод filtering_stream выполняется при уничтожении объекта. Таким образом, я не знаю, можно ли это сделать чисто с shared_ptr. Я не знаю, был ли файл или поток уничтожен первым, и я предполагаю, что это приводит к проблемам.
Как вы думаете, реализация getCompressedStream таким образом возможна? Что бы вы изменили?
Спасибо
Редактировать: Это работает, если я переключаюсь на обычные указатели вместо общих указателей и явно удаляю поток перед файлом.
1 ответ
Я не уверен. Настоящая проблема в том, что вы никогда не закрываете ofstream
Таким образом, вы понятия не имеете, что происходит. (За исключением исключений, когда вы все равно собираетесь удалить новый файл, вы должны проверить статусofstream
возражать после закрытия, чтобы узнать, все ли получилось или нет.) В целом, ваше решение кажется мне слишком сложным; Вы пытаетесь сделать слишком много в одной функции. Способ, которым я обычно делаю это (с моей собственной фильтрацией streambuf, которая предшествует буст-версиям на несколько лет), заключается в следующем:
std::ofstream file( filename.c_str() );
if ( compressed ) {
CompressedStreambuf c( file );
outputData( file );
} else {
outputDate( file );
}
file.close();
if ( !file ) {
remove( filename.c_str() ); // Since it isn't complete
// Ensure that program return code is failure.
}
Конечно, мой собственный фильтр streambuf работает немного иначе, чем Boost: конструктор принимает ostream
вставляет фильтр перед ostream
, а деструктор сбрасывает и удаляет фильтр (вариант RAII). Но не должно быть слишком сложно создать оболочку классов Boost для поддержки этого.
Преимущество этого решения состоит в том, что все гарантированно будет построено и уничтожено в правильном, вложенном порядке, потому что нет динамического распределения, которое допускало бы произвольный порядок.