当我们尝试在文件中提取带有 istream::getline() 和 std::getline() 的 `eof` 字符的行时,实际发生了什么

What's actually happens when we try to extract line in file after which `eof` character is present with istream::getline() and std::getline()

roha.txt

I really love to spend time with you.
Let's go for coffee someday.
Enjoy whole day and cherish the memories.

代码-1

#include <iostream>
#include <fstream>


int main()
{
    char str[100];

    std::ifstream fin;
    fin.open("roha.txt", std::ios::in);

   for(int i=0; i<=3; i++)
   {
        std::cout<<bool(fin.getline(str,100) )<<" "<<str<<fin.fail()<<"\n";
   }

}

输出

1 I really love to spend time with you.0
1 Let's go for coffee someday.0
1 Enjoy whole day and cherish the memories.0
0 1

Code-2

#include <iostream>
#include <fstream>
#include <string>
using std::string;

int main()
{
   string str;

    std::ifstream fin;
    fin.open("roha.txt", std::ios::in);

    for(int i=0; i<=3; i++)
    {
        std::cout<<bool(std::getline(fin,str) )<<" "<<str<<fin.fail()<<"\n";
    }

}

输出

1 I really love to spend time with you.0
1 Let's go for coffee someday.0
1 Enjoy whole day and cherish the memories.0
0 Enjoy whole day and cherish the memories.1

我知道C-style char arrayistream::getlinestringstd::getline是不一样的。但我想知道到底发生了什么。

我猜测对于 stringstd::getline,它会提取第 1 次、第 2 次的字符串,当它尝试提取第 3 次时它会看到 eof,因此它会在之前提取eof.

下次我们尝试提取它时,正好遇到 eof 所以它没有提取任何东西并设置 fail-bit.

string str 没有被修改,所以当我们尝试打印它时,只会打印最后提取的字符串。

不知道我的想法对不对...

此外,关于 istream::getline()C-style char array

,我也无法提出任何此类案例

引用标准,第 21.3.3.4 节插入器和提取器 [string.io]:

第 6 条:

[…] After constructing a sentry object, if the sentry converts to true, calls str.erase() and then extracts characters from is and appends them to str […] until any of the following occurs:

  • end-of-file occurs on the input sequence (in which case, the getline function calls is.setstate(ios_base::eofbit)).
  • […]

第 29.7.4.1.3 节 Class basic_istream::sentry:

explicit sentry(basic_istream<charT, traits>& is, bool noskipws = false); Effects: If is.good() is false, calls is.setstate(failbit) […] If, after any preparation is completed, is.good() is true, ok_ != false otherwise, ok_ == false. During preparation, the constructor may call setstate(failbit) […]

explicit operator bool() const; Returns: ok_

那么,字符串版本发生了什么:

  1. 您提取了最后一个字符串。这会设置 eofbit,但不会设置 failbit
  2. 你又上线了
  3. getline构造哨兵
  4. 哨兵检查is.good()。这是错误的,因为设置了 eofbit
  5. 哨兵设置failbit并将其成员ok_设置为false
  6. getline 函数检查哨兵是否为真(运算符 bool)。这是假的
  7. 清除旧字符串之前的 getline 函数 returns

第 29.7.4.3 节未格式化的输入函数

条款 21(这是关于 C 字符串版本):

In any case, if n is greater than zero, it then stores a null character (using charT()) into the next successive location of the array

其余的写法与字符串版本类似。换句话说,getline 的 C 字符串版本总是存储一个 '[=33=]' 字符,即使它失败了。 std::string 版本没有,大概是因为如果您忘记检查故障位,它不会引入与 C 版本相同的内存安全问题。