3

如果我这样做:

ifstream stream("somefilewhichopenssuccesfully.txt");
string token;
if( stream >> token )
    cout << token;
else
    cout << token;

第二种情况下的输出是否保证为空字符串?我似乎无法在 cplusplus.com 上找到答案。

谢谢!

4

3 回答 3

2

第二种情况下的输出是否保证为空字符串?

答案是:不,因为它取决于,如下所述。

因为else只有在尝试从流中读取失败时才会执行块,并且在读取过程中随时可能发生这种情况。

  • 如果它在第一次尝试时失败,则不会从流中提取字符,因此token将是空的(原样)。

  • 如果在几次读取后失败,则token不会为空。它将包含到目前为止从流中成功读取的字符。

标准中的第 21.3.7.9 节说,

从构造一个哨兵对象 k 开始,就好像 k 是由 typename basic_istream::sentry k(is) 构造的。如果 bool(k) 为真,它调用 str.erase() 然后从 is 中提取字符并将它们附加到 str ,就像调用 str.append(1,c) 一样。如果 is.width() 大于零,则追加的最大字符数为 is.width();否则 n 是 str.max_size()。字符被提取并附加,直到发生以下任何情况

— 存储 n 个字符;

— 文件结束出现在输入序列上;

— isspace(c,is.getloc()) 对于下一个可用的输入字符 c 为真。

提取最后一个字符(如果有)后,调用 is.width(0) 并销毁哨兵对象 k。

如果函数没有提取字符,它会调用 is.setstate(ios::failbit),这可能会抛出 ios_base::failure (27.4.4.3)。


另请注意,标准中的第 21.3.1/2 节保证默认构造的字符串将为空。标准说它的大小将为零,这意味着它是空的。

于 2011-04-17T19:04:13.290 回答
1

我删除了原来的答案,因为我想对此进行测试。这就是我所看到的,如果读取时出现错误(在此上下文中不计算 EOF),则修改原始字符串并且分支会看到修改后的版本。为了测试我做了以下,创建了一个 2Gb 文件(touch然后truncate),上面的代码要读取。在代码运行时,删除了文件(这应该设置failbit- 我认为)。立即停止读取,但字符串被修改 - 它具有更大的大小。

对我来说,这表明即使流操作失败,字符串也会被修改。

于 2011-04-17T19:05:09.653 回答
0

不,即使操作失败,字符串也会包含到目前为止提取的字符。

该标准说(§21.4.8.9):

效果:表现为格式化输入函数 (27.7.2.2.1)。构造sentry对象后,如果哨兵转换为 true,则调用str.erase()然后从中提取字符is并将它们附加到,str就好像通过调用str.append(1,c). 如果is.width()大于零,则追加的最大字符数为is.width(); 否则 n 是str.max_size()。字符被提取和附加,直到发生以下任何情况:
— n 个字符被存储;
— 文件结束出现在输入序列上;
isspace(c,is.getloc())对下一个可用的输入字符 c 为真。

于 2011-04-17T19:51:45.083 回答