Безопасная перегрузка потокового оператора >>

Существует масса информации о перегрузке operator<< подражать toString() метод, который преобразует сложный объект в строку. Я заинтересован в реализации обратного, operator>> десериализовать строку в объект.

Осматривая STL Источник, я собрал это:

istream &operator>>(istream &, Object &);

будет правильной сигнатурой функции для десериализации объекта типа Object, К сожалению, я был в недоумении, как правильно реализовать это, в частности, как обрабатывать ошибки:

  1. Как указать неверные данные в потоке? Бросить исключение?
  2. В каком состоянии должен быть поток, если в потоке есть искаженные данные?
  3. Должны ли быть сброшены какие-либо флаги перед возвратом ссылки для объединения операторов?

3 ответа

Решение
  1. Как указать неверные данные в потоке? Бросить исключение?

Вы должны установить fail немного. Если пользователь потока хочет, чтобы исключение было выдано, он может настроить поток (используя istream::exceptions), и поток будет выбрасывать соответственно. Я бы сделал это так, то

stream.setstate(ios_base::failbit);
  1. В каком состоянии должен быть поток, если в потоке есть искаженные данные?

Для искаженных данных, которые не соответствуют формату, который вы хотите прочитать, вы обычно должны установить fail немного. Для ошибок, специфичных для внутреннего потока, bad бит используется (например, если нет буфера, подключенного к потоку).

  1. Должны ли быть сброшены какие-либо флаги перед возвратом ссылки для цепочки операторов?

Я не слышал о такой вещи.


Чтобы проверить, находится ли поток в хорошем состоянии, вы можете использовать istream::sentry учебный класс. Создайте объект этого, передавая поток и true (сказать, чтобы не пропускать пробелы немедленно). Часовой оценит false если eof, fail или же bad бит установлен.

istream::sentry s(stream, true);
if(!s) return stream;
// now, go on extracting data...

Некоторые дополнительные заметки:

  • при реализации оператора >> вам, вероятно, следует рассмотреть возможность использования bufstream, а не других перегрузок оператора >>;

  • исключения, возникающие во время операции, должны быть переведены в бит-бит или бит-бит (члены streambuf могут выдавать, в зависимости от используемого класса);

  • установка состояния может скинуть; если вы устанавливаете состояние после перехвата исключения, вы должны распространять исходное исключение, а не исключение, выброшенное setsets;

  • ширина - это поле, на которое следует обратить внимание. Если вы принимаете это во внимание, вы должны сбросить его на 0. Если вы используете другой оператор >> для выполнения основных работ, вы должны вычислить ширину, которую вы передаете, из полученной вами;

  • рассмотрите возможность принять во внимание локаль.

Lange и Kreft (стандартные C++ IOStreams и Locales) конвертируют это еще более подробно. Они дают код шаблона для обработки ошибок, который занимает около одной страницы.

Что касается флагов, я не знаю, есть ли где-нибудь какие-либо стандарты, но это хорошая идея, чтобы сбросить их.

У Boost есть аккуратные raii-оболочки для этого: IO State Savers

Другие вопросы по тегам