2015-11-11 2 views
1

Подумайте, что здесь происходит. Я пытался пропустить это через gdb, но, похоже, не может получить отладочную версию/код libstdC++, поэтому можно надеяться, что кто-то, кто знает их потоки, может помочь? В приведенном ниже коде, ключ бит петля в то время как:C++ stringstream и fail vs eof

#include <iostream> 
#include <string> 
#include <vector> 
#include <algorithm> 
#include <iomanip> 
#include <sstream> 
using namespace std; 
void printer(int i) { 
     cout << i << ", "; 
} 
int main() 
{ 
     string s; 
     getline(cin, s); 
     stringstream input(s); 
     vector<int> v1; 
     int i; 
     while (!input.fail()) 
     { 
       input >> i; 
       v1.push_back(i); 
     } 
     for_each(v1.begin(), v1.end(), printer); 
     return 0; 
} 

Когда я запускаю это и указать номер, это, кажется, добавить, что число дважды в векторе. Если я изменил условие цикла while на eof() (в отличие от fail()), все будет вести себя так, как я ожидал.

Предполагается, что извлечение operator>> должно извлекать значения из потока, как возможно, что последовательные вызовы продолжают производить результат?

Я предполагаю, что я не думал об этом совсем верно (это 2:30 утра LocalTime, так что, возможно, что-то делать с этим!)

Использование GCC версии 4.9.2 (Ubuntu 4.9.2 -0ubuntu1 ~ 12.04)

ответ

4

Это тонко замаскированная версия обычной ошибки incorrect use of eof().

Петля должна быть:

while (input >> i) 
    v1.push_back(i); 

В реальном коде вы еще push_back(i) даже после того, как не удалось прочитать.

В версии с eof() он может или не может устанавливать флаг eof при чтении предыдущего значения; вы не можете полагаться на то, что вы наблюдаете.

+0

Я вижу - ваша последняя редакция отвечает на мой вопрос: «Почему он работает с eof()?» - спасибо - в принципе, если вы когда-нибудь собираетесь извлечь из потока в цикле, извлечение, происходящее в состоянии цикла, - это канонический путь, который я принимаю? – aho

+0

@aho Если не каноническое, это по крайней мере крайне рекомендуется. – user4581301

+1

@aho Обычно это хорошо, но для некоторых типов данных вы можете прочитать частичное значение, а затем пропустить и одновременно нажать eof: флаги состояния потока останутся такими же, как для условия eof без частичного значения , трудно распознать и отреагировать на фиктивное частичное значение. Например, если вы переходите к «double», а поток имеет только «5E» - это неудачное преобразование, а также eof. Для тех случаев, когда вам это нравится, вы можете использовать 'while (input >> std :: skipws &&! Input.eof() && input >> my_double)', тогда бит отказа будет установлен только в случае сбоя анализа. –