C ++: странное поведение с std :: istream или обходом вокруг часового - PullRequest
3 голосов
/ 08 февраля 2012

Эта небольшая пользовательская функция getline была дана как ответ на вопрос об обработке разных концов строк.

Функция работала великолепно, пока не была отредактирована 2 дня назад, чтобы не пропускать начальные пробелы для каждой строки.Однако после редактирования программа переходит в бесконечный цикл.Единственное изменение, внесенное в код, было следующей строкой, которая была изменена с этого:

std::istream::sentry se(is);  // When this line is enabled, the program executes
                              // correctly (no infinite loop) but it does skip
                              // leading white spaces

на это:

std::istream::sentry se(is, true); // With this line enabled, the program goes 
                                   // into infinite loop inside the while loop  
                                   // of the main function.

Может кто-нибудь помочь мне объяснить, почему программа выполняет циклы бесконечно, еслимы указываем, чтобы не пропускать пробелы?

Вот полная программа ...

std::istream& safeGetline(std::istream& is, std::string& t)
{
    t.clear();

    // The characters in the stream are read one-by-one using a std::streambuf.
    // That is faster than reading them one-by-one using the std::istream.
    // Code that uses streambuf this way must be guarded by a sentry object.
    // The sentry object performs various tasks,
    // such as thread synchronization and updating the stream state.

    std::istream::sentry se(is, true);
    std::streambuf* sb = is.rdbuf();

    for(;;) {
        int c = sb->sbumpc();
        switch (c) {
        case '\r':
            c = sb->sgetc();
            if(c == '\n')
                sb->sbumpc();
            return is;
        case '\n':
        case EOF:
            return is;
        default:
            t += (char)c;
        }
    }
}

А вот тестовая программа:

int main()
{
    std::string path = "end_of_line_test.txt"

    std::ifstream ifs(path.c_str());
    if(!ifs) {
        std::cout << "Failed to open the file." << std::endl;
        return EXIT_FAILURE;
    }

    int n = 0;
    std::string t;
    while(safeGetline(ifs, t))   //<---- INFINITE LOOP happens here. <----
        std::cout << "\nLine " << ++n << ":" << t << std::endl;

    std::cout << "\nThe file contains " << n << " lines." << std::endl;
    return EXIT_SUCCESS;
}

Я также пыталсядобавить эту строку в самом начале функции, но это не имело никакого значения ... программа все еще бесконечно зацикливалась в цикле while основной функции.

is.setf(0, std::ios::skipws);

Файл end_of_line_test.txt - это текстовый файл, который содержит только следующие две строки:

   "1234" // A line with leading white spaces
"5678"    // A line without leading white spaces

1 Ответ

6 голосов
/ 08 февраля 2012

Проблема в том, что safeGetLine никогда не устанавливает состояние eof() для потока.

Когда вы используете std::istream::sentry se(is);, , он попытается прочитать пробел и обнаружит, что вынаходятся в конце файла.Когда вы просите его не искать пробелы, это никогда не происходит.

Я полагаю, вам следует добавить is.setstate(ios_base::eofbit) к условию EOF для функции.

...