У меня есть некоторые данные, которые я хочу отформатировать и вывести, либо в необработанном текстовом файле, либо в сжатом текстовом файле .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 таким образом возможна? Что бы вы изменили?
Спасибо
редактировать : Это работает, если я переключаюсь на обычные указатели вместо общих указателей и явно удаляю поток перед файлом.
Я не уверен. Настоящая проблема заключается в том, что вы никогда явно не
закрой 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 для поддержки
этот.
Преимущество этого решения в том, что все гарантировано
быть построенным и разрушенным в правильном, вложенном порядке,
потому что нет динамического распределения, которое позволило бы
произвольный порядок.
Других решений пока нет …