Безопасная перегрузка оператора потока >>
Там имеется масса информации о перегрузке operator<<
, чтобы имитировать метод toString()
-style, который преобразует сложный объект в строку. Я также заинтересован в реализации обратного, operator>>
для десериализации строки в объект.
Проверяя источник STL
, я понял, что:
istream &operator>>(istream &, Object &);
будет правильной сигнатурой функции для десериализации объекта типа Object
. К сожалению, я был в недоумении, как правильно это реализовать - в частности, как обрабатывать ошибки:
- Как указать недопустимые данные в потоке? Выбросить исключение?
- В каком состоянии должен быть поток, если в потоке есть искаженные данные?
- Должны ли какие-либо флаги reset перед возвратом ссылки на цепочку операторов?
Ответы
Ответ 1
- Как указать недопустимые данные в потоке? Выбросить исключение?
Вы должны установить бит fail
. Если пользователь потока хочет, чтобы исключение было выбрано, он может настроить поток (используя istream::exceptions
), и поток будет выбрасываться соответствующим образом. Я сделал бы это так, тогда
stream.setstate(ios_base::failbit);
- В каком состоянии должен быть поток, если в потоке есть искаженные данные?
Для искаженных данных, которые не соответствуют формату, который вы хотите прочитать, вы обычно должны устанавливать бит fail
. Для внутренних ошибок, связанных с потоком, используется бит bad
(например, если буфер не подключен к потоку).
- Должны ли какие-либо флаги reset перед возвратом ссылки на цепочку операторов?
Я не слышал об этом.
Чтобы проверить, находится ли поток в хорошем состоянии, вы можете использовать класс istream::sentry
. Создайте его объект, передав поток и true
(чтобы он не пропустил пробел сразу). Часовой будет оценивать до false
, если бит eof
, fail
или bad
установлен.
istream::sentry s(stream, true);
if(!s) return stream;
// now, go on extracting data...
Ответ 2
Некоторые дополнительные примечания:
-
при реализации оператора → , вам, вероятно, следует рассмотреть возможность использования
bufstream, а не другие перегрузки оператора → ;
-
исключения, возникающие во время операции, должны быть переведены на
failbit или badbit (члены streambuf могут бросать, в зависимости от
класс);
-
настройка состояния может бросить; если вы установили состояние после
исключение, вы должны распространять исходное исключение, а не одно
выбрано setstate;
-
ширина - это поле, на которое вы должны обратить внимание. Если ты
учитывая это, вы должны reset его равным 0. Если вы используете другие
оператор → делать базовые работы, вам нужно вычислить ширину, которую вы передаете
от того, которое вы получили;
-
подумайте о том, чтобы учитывать локаль.
Lange и Kreft (стандартные IOStreams и локали С++) конвертируют это в четное
более подробно. Они дают код шаблона для обработки ошибок, который принимает
около одной страницы.
Ответ 3
Что касается флагов, я не знаю, есть ли какой-либо стандарт где-то, но это хорошая идея для reset их.
Boost имеет опрятные обтекатели raii для этого: IO State Savers