简体   繁体   English

C ++:使用std :: istream或sentry环绕的奇怪行为

[英]C++: strange behavior with std::istream or sentry wrap around

This small custom getline function was given as an answer to a question about handling different line endings. 这个小的自定义getline函数是作为一个关于处理不同行结尾的问题的答案

The function worked great until it was edited 2 days ago to make it not skip leading white spaces for each line. 该功能非常有效,直到2天前编辑,使其不会跳过每行的前导空格。 However, after the edit, the program now goes into an infinite loop. 但是,在编辑之后,程序现在进入无限循环。 The only change done to the code was this following line which was changed from this: 对代码进行的唯一更改是以下更改的行:

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

to this: 对此:

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

Can someone please help me explain why the program loops infinitely if we specify to not skip white spaces? 如果我们指定不跳过空格,有人可以帮我解释为什么程序无限循环?

Here is the full program... 这是完整的程序......

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;
        }
    }
}

And here is a test program: 这是一个测试程序:

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;
}

I also tried to add this line at the very beginning of the function but it made no difference... the program still looped infinitely in the while loop of the main function. 我也尝试在函数的最开始添加这一行,但没有区别......程序仍然在main函数的while循环中无限循环。

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

The file end_of_line_test.txt is a text file which contains only the following two lines: 文件end_of_line_test.txt是一个文本文件,它只包含以下两行:

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

The problem is that safeGetLine never sets the eof() state for the stream. 问题是safeGetLine从不为流设置eof()状态。

When you use std::istream::sentry se(is); 当你使用std::istream::sentry se(is); , it will try to read whitespace and discover that you are at end-of-file. 会尝试读取空格并发现您处于文件末尾。 When you ask it not to look for whitespace, this never happens. 当你要求它不要寻找空白时,这种情况永远不会发生。

I believe you should add is.setstate(ios_base::eofbit) to the EOF condition for the function. 我相信你应该将is.setstate(ios_base::eofbit)添加到该函数的EOF条件中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM