Почему stringstream >> меняет значение цели при сбое?

c++ state stringstream cin

2531 просмотра

2 ответа

Из TC ++ PL Страуструпа, 3-е издание, раздел 21.3.3:

Если мы попытаемся прочитать переменную v, и операция не удастся, значение v должно быть неизменным (оно не изменится, если v является одним из типов, обрабатываемых функциями-членами istream или ostream).

Следующий пример противоречит приведенной выше цитате. Основываясь на приведенной выше цитате, я ожидал, что значение v останется неизменным - но оно обнуляется. Чем объясняется это кажущееся противоречивое поведение?

#include <iostream>
#include <sstream>

int main( )
{
    std::stringstream  ss;

    ss  << "The quick brown fox.";

    int  v = 123;

    std::cout << "Before: " << v << "\n";

    if( ss >> v )
    {
        std::cout << "Strange -- was successful at reading a word into an int!\n";
    }

    std::cout << "After: " << v << "\n";

    if( ss.rdstate() & std::stringstream::eofbit  ) std::cout << "state: eofbit\n";
    if( ss.rdstate() & std::stringstream::failbit ) std::cout << "state: failbit\n";
    if( ss.rdstate() & std::stringstream::badbit  ) std::cout << "state: badbit\n";

    return 1;
}

Вывод, который я получаю, используя x86_64-w64-mingw32-g ++. Exe (rubenvb-4.7.2-release) 4.7.2:

Before: 123
After: 0
state: failbit

Благодарю.

Автор: user1823664 Источник Размещён: 12.09.2019 01:39

Ответы (2)


59 плюса

Решение

Из этой ссылки :

Если извлечение завершается неудачно (например, если буква была введена там, где ожидается цифра), значение остается неизменным, и бит сбоя устанавливается ( до C ++ 11 )

Если извлечение завершается неудачно, в значение записывается ноль, и бит сбоя устанавливается. Если извлечение приводит к тому, что значение слишком велико или слишком мало, чтобы поместиться в значение, записывается std :: numeric_limits :: max () или std :: numeric_limits :: min () и устанавливается флаг сбоя. ( начиная с C ++ 11 )

Кажется, ваш компилятор компилируется в режиме C ++ 11, что меняет поведение.


Оператор ввода использует фасет локали std::num_get, getфункция которого вызывается do_get. Для C ++ 11 указано использование std::strtollet. и др. тип функций. До C ++ 11 он, очевидно, использовал std::scanfсинтаксический анализ стилей (по ссылке, у меня нет доступа к спецификации C ++ 03) для извлечения чисел. Изменение в поведении связано с этим изменением при разборе ввода.

Автор: Some programmer dude Размещён: 14.11.2012 12:45

4 плюса

Оператор >> является оператором форматированного ввода.
Таким образом, это зависит от локали того, как ввод читается из потока:

[Istream.formatted.arithmetic]

Как и в случае вставок, эти экстракторы зависят от объекта локали num_get <> (22.4.2.1) для выполнения анализа данных входного потока. Эти экстракторы ведут себя как отформатированные функции ввода (как описано в 27.7.2.2.1). После того, как часовой объект создан, преобразование происходит так, как если бы оно выполнялось следующим фрагментом кода:

   typedef num_get< charT,istreambuf_iterator<charT,traits> > numget;
   iostate err = iostate::goodbit;
   use_facet< numget >(loc).get(*this, 0, *this, err, val);
   setstate(err);

Как мы видим выше, значение на самом деле задается numgetаспектом локали, вставленной в поток.

виртуальные функции num_get [facet.num.get.virtuals]

Этап 3:

Числовое значение, которое будет сохранено, может быть одним из:

  • ноль, если функция преобразования не может преобразовать все поле. ios_base :: failbit назначается для err.
  • наиболее положительное представимое значение, если поле представляет слишком большое положительное значение, чтобы быть представленным в val. ios_base :: failbit назначается для err.
  • самое отрицательное представимое значение или ноль для целого типа без знака, если поле представляет слишком большое отрицательное значение, чтобы быть представленным в val. ios_base :: failbit назначается для err.

Определение стадии 3 резко изменилось между n2723 -> n2798

Где я могу найти текущие стандартные документы C или C ++?

виртуальные функции num_get [facet.num.get.virtuals]

Этап 3: Результатом обработки этапа 2 может быть один из:

  • На этапе 2 была накоплена последовательность символов, которая преобразуется (согласно правилам scanf) в значение типа val. Это значение хранится в val, а ios_base :: goodbit - в err.
  • Последовательность символов, накопленная на этапе 2, заставила бы scanf сообщить об ошибке ввода. ios_base :: failbit назначается для err.
Автор: Martin York Размещён: 14.11.2012 01:42
Вопросы из категории :
32x32