istream_iterator попытается проанализировать неверные данные - PullRequest
1 голос
/ 17 августа 2011

Привет, я надеялся, что кто-нибудь поможет понять это поведение приведенного ниже кода.

#include <iostream>
#include <algorithm>
#include <string>
#include <limits>
#include <fstream>
#include <iterator>
#include <stdexcept>


struct asound_stanza
{
    unsigned index;
    std::string name;

    friend std::istream &operator>>(std::istream &is, asound_stanza &stan)
    {
        is >> stan.index;
        if(!is.good())
            return is;
        std::getline(is, stan.name);
        std::string::const_iterator
            eol   = stan.name.cend(),
            start = std::find(stan.name.cbegin(), eol, '['),
            end   = std::find(start, eol, ' ');
        stan.name = std::string(++start, end);
        is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        // std::istream_iterator<char> it;
        // while(*it++!=0x0a);
        return is;
    }
};

int main()
{
    std::ifstream is("/proc/asound/cards", std::ifstream::in); 
    std::istream_iterator<asound_stanza> it(is), end;
    unsigned devid = 0;
    std::for_each(it, end, [&](const asound_stanza &stan)->void{
        if(stan.name!="CODEC")
            return;
        devid = stan.index;
    });
    std::cout << devid;
    return 0;
}

это работает, но у меня есть несколько вопросов. после того, как все действительные итерации сделаны, он идет головой и пытается проанализировать другую, которая неизбежно завершается неудачей (отсюда if(!is.good())... _). Он пытается разобрать его, но никогда не передает окончательную искаженную структуру в лямбда-выражение. Почему не так? Это потому, что потоки не очень хороши (), поэтому не надо пытаться передать их?

Кроме того, как мне заставить его даже не пытаться разобрать окончательную структуру (каждая строфа заканчивается новой строкой (0x0a), поэтому я бы подумал, что игнорирование потока до новой строки вызовет EOF на последняя действительная итерация, но это не так.

Спасибо за ваше руководство.

Также не стесняйтесь передавать комментарии о правильности кодирования.

PS: мой файл выглядит так

0 [Intel          ]: HDA-Intel - HDA Intel
                     HDA Intel at 0xfc500000 irq 46
1 [HDMI           ]: HDA-Intel - HDA ATI HDMI
                     HDA ATI HDMI at 0xfc010000 irq 47
2 [CODEC          ]: USB-Audio - USB Audio CODEC
                     Burr-Brown from TI USB Audio CODEC at usb-0000:00:1d.7-3.1, full speed

Ответы [ 2 ]

1 голос
/ 17 августа 2011

Если поток находится в недопустимом состоянии или если попытка чтения из потока внутри оператора >> завершается неудачно и устанавливает поток в недопустимое состояние, istream_iterator устанавливает себя в конец позиции потока. Таким образом, итерация заканчивается, даже не глядя на частично разобранный объект.

1 голос
/ 17 августа 2011

Ваш код должен выглядеть следующим образом:

friend std::istream &operator>>(std::istream &is, asound_stanza &stan)
{
    if ( !(is >> stan.index) )
        return is;  //return if couldn't read unsigned int

    if(std::getline(is, stan.name))//go inside ONLY IF read is successful
    {
       std::string::const_iterator 
       eol  =stan.name.cend(),
       start=std::find(stan.name.cbegin(), eol, '['),
       end  =std::find(start, eol, ' ');
       stan.name=std::string(++start, end);    
       is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    return is;
}

Прочитайте комментарии в моей модификации выше!

Так как это обсуждалось очень много раз, и я отвечал много раз раньшечто я не хочу повторять это снова.Пожалуйста, прочитайте мой другой ответ, который объясняет саму вещь:

...