Эта проблема
На данный момент поддержка исключений для потоков ужасна. Когда библиотека Boost.System была принята в C ++ 11, создалось впечатление, что возможно исключения улучшатся. Все изменения были заменены std::exception
на std::system_error
. Хотя <system_error>
сама по себе является хорошей библиотекой для разработчиков, стандартный комитет и разработчики стандартной библиотеки не предприняли никаких шагов для ее использования для улучшения сообщений об исключениях.
Чтобы понять, насколько это ужасно, вот краткое изложение того, что происходит:
Произошла ошибка.
setstate
используется для установкиbadbit
илиfailbit
.clear
вызываетсяsetstate
.Если включены исключения,
clear
выдастios_base::failure
.
Да, это означает, что для ВСЕХ ошибок выдается одно и то же бесполезное сообщение об исключении. Это указано на уровне basic_ios
, поэтому от этой проблемы страдают все производные классы. Оскорбительная цитата:
[iostate.flags] / 4 Эффекты: если
((state | (rdbuf() ? goodbit : badbit)) & exceptions()) == 0
, возвращается. В противном случае функция создает объектfail
классаbasic_ios::failure
(27.5.3.1.1), созданный с использованием значений аргументов, определенных реализацией.
Вот пример того, что дают нам «значения аргументов, определяемые реализацией»:
ios_base::clear: unspecified iostream_category error
Есть ли простое решение?
Ни Boost.Filesystem
, ни Boost.Iostreams
не заменяют <iostream>
. Первая представляет собой библиотеку для переносимой работы с файловой системой (и, вероятно, появится в следующей версии C ++), а вторая имеет какое-то отношение к ... Источникам и приемникам. В документации указано, что она в любом случае делегирует исключения ios_base::failure
. Boost.Filesystem
предоставляет <boost/filesystem/fstream.hpp>
, который использует path
вместо const char*
аргументов для open()
. Он показывает пример того, как можно наследовать классы стандартной библиотеки:
template < class charT, class traits = std::char_traits<charT> >
class basic_ifstream : public std::basic_ifstream<charT,traits>
{
private: // disallow copying
basic_ifstream(const basic_ifstream&);
const basic_ifstream& operator=(const basic_ifstream&);
public:
basic_ifstream() {}
// use two signatures, rather than one signature with default second
// argument, to workaround VC++ 7.1 bug (ID VSWhidbey 38416)
explicit basic_ifstream(const path& p)
: std::basic_ifstream<charT,traits>(p.BOOST_FILESYSTEM_C_STR, std::ios_base::in) {}
basic_ifstream(const path& p, std::ios_base::openmode mode)
: std::basic_ifstream<charT,traits>(p.BOOST_FILESYSTEM_C_STR, mode) {}
void open(const path& p)
{ std::basic_ifstream<charT,traits>::open(p.BOOST_FILESYSTEM_C_STR, std::ios_base::in); }
void open(const path& p, std::ios_base::openmode mode)
{ std::basic_ifstream<charT,traits>::open(p.BOOST_FILESYSTEM_C_STR, mode); }
virtual ~basic_ifstream() {}
};
Это изящный трюк, за исключением того, что наша вызывающая нарушение функция не виртуальная, и вплоть до basic_ios
происходит комбинаторный взрыв того, что мы должны переопределить:
Я подозреваю, что необходима полная перезапись, потому что простой замены clear()
будет недостаточно. Поток может завершиться ошибкой по нескольким причинам, но возникает только один тип исключения. Хотя std::system_error
дает нам лучшие инструменты для выражения ошибок, это не помогает, если, опять же, нет способа определить источник ошибки.
Однако я не писатель библиотеки и не хочу брать на себя эту задачу. Есть ли другие варианты, кроме тех, которые я перечислил?
cstdio
, любую библиотеку или системные вызовы. - person M.M   schedule 05.10.2015