C++:std::istream 或哨兵环绕的奇怪行为
这个小型自定义 getline 函数作为 答案给出 关于处理不同行结尾的问题。
该函数一直运行良好,直到两天前对其进行了编辑,使其不会跳过每行的前导空格。然而,编辑后,程序现在进入无限循环。对代码所做的唯一更改是以下行,该行从以下内容更改
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
This small custom getline function was given as an answer to a question about handling different line endings.
The function worked great until it was edited 2 days ago to make it not skip leading white spaces for each line. 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.
is.setf(0, std::ios::skipws);
The file end_of_line_test.txt is a text file which contains only the following two lines:
"1234" // A line with leading white spaces
"5678" // A line without leading white spaces
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题是
safeGetLine
永远不会设置流的eof()
状态。当您使用 std::istream::sentry se(is); 时,它会尝试读取空格并发现您位于文件末尾。当你要求它不寻找空格时,这种情况永远不会发生。
我相信您应该将 is.setstate(ios_base::eofbit) 添加到函数的 EOF 条件中。
The problem is that
safeGetLine
never sets theeof()
state for the stream.When you use
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.