2012-02-08 32 views
3

这个小的自定义getline函数被作为一个answer给出一个关于处理不同的行尾的问题。C++:奇怪的行为与std :: istream或哨兵环绕

该功能在两天前编辑完成,直到它不会跳过每行的前导空白为止。但是,在编辑之后,程序现在进入无限循环。做代码中的唯一的变化是这下面的行这是从这个改变:

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 
+0

@templatetypedef我正在使用最新版本的命令行编译器,用于在Windows xp 32位上运行的visual C++。如果我将哨兵行更改为“std :: istream :: sentry se(is);”该程序的工作原理,但如果我把它改回“std :: istream :: sentry se(is,true);”该程序崩溃。在你的测试文件中,你是否有任何行中的前导空格? – 2012-02-08 05:28:10

+0

你得到了什么具体的崩溃?我们可以得到堆栈跟踪吗? – templatetypedef 2012-02-08 05:29:10

+0

为了演示崩溃,我在while循环内改了一行。我得到了无尽的打印输出,显示了行号和数字零的内容。我不知道如何做一个堆栈跟踪(初学者,抱歉)。 – 2012-02-08 05:34:13

回答

6

的问题是safeGetLine不落eof()状态流。

当您使用std::istream::sentry se(is);,时,将尝试读取空格并发现您处于文件结尾。当你要求它不要寻找空白时,这绝不会发生。

我相信你应该添加is.setstate(ios_base::eofbit)到函数的EOF条件。

+0

非常感谢您的回答。我已经加了'是的。getline函数中的行'case EOF:'和'return is;'之间的setstate(ios_base :: eofbit)'。但是,现在程序打印完一行后就停止了。我是否需要清除函数开头的流状态位,以便每次都执行?或者那是危险的? – 2012-02-08 19:47:57

+0

您必须将EOF案件从“\ n”案件中分离出来,因为它们(现在)是不同的。 – 2012-02-08 19:51:37

+0

@Bo ...非常感谢你,你的回答完全解决了问题!!!!!!我现在能够获得我正在寻找的行为。 – 2012-02-08 23:46:53