C++年诺斯基普斯的示范

Demonstration of noskipws in C++

本文关键字:C++      更新时间:2023-10-16

我在C++中尝试了noskipws操纵器,我写了以下代码。

#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
string first, middle, last;
istringstream("G B Shaw") >> first >> middle >> last;
cout << "Default behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << 'n';
istringstream("G B Shaw") >> noskipws >> first >> middle >> last;
cout << "noskipws behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << 'n';
}

我期望以下输出:

预期输出

Default behavior: First Name = G, Middle Name = B, Last Name = Shaw
noskipws behavior: First Name = G, Middle Name = , Last Name = B

输出

Default behavior: First Name = G, Middle Name = B, Last Name = Shaw
noskipws behavior: First Name = G, Middle Name = , Last Name = Shaw

我修改了这段代码,使其适用于这样的字符,并且工作得很好。

#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
char first, middle, last;
istringstream("G B S") >> first >> middle >> last;
cout << "Default behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << 'n';
istringstream("G B S") >> noskipws >> first >> middle >> last;
cout << "noskipws behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << 'n';
}

我知道 cin 是如何工作的,但我无法弄清楚为什么它在string的情况下以这种方式工作。

std::istringstream("G B S") >> std::noskipws >> first >> middle >> last;

对字符串执行提取时,首先清除字符串并将字符插入其缓冲区。

21.4.8.9 机械臂和提取器

template<class charT, class traits, class Allocator>
basic_istream<charT, traits>&
operator>>(basic_istream<charT, traits>& is,
basic_string<charT, traits, Allocator>& str);

效果:表现为格式化输入函数 (27.7.2.2.1)。构造哨兵对象后,如果哨兵转换为true调用str.erase(),然后从is中提取字符并将其附加到str,就像通过调用str.append(1, c).[...]

第一次读取会将字符串"G"提取到first中。对于第二次提取,不会提取任何内容,因为设置了std::noskipws格式标志,从而禁用了前导空格的清除。因此,字符串被清除,然后提取失败,因为没有输入任何字符。以下是上述条款的延续:

21.4.8.9 机械臂和提取器(续)

[...]提取并追加字符,直到发生以下任一情况:

  • 存储n字符;

  • 文件结尾出现在输入序列上;

  • 对于下一个可用输入,isspace(c, is.getloc())为 true 角色c.

当流确定提取失败时,std::ios_base::failbit设置为流状态,指示错误。

从此时开始,除非清除流状态,否则任何和所有 I/O 尝试都将失败。提取器变得不可操作,并且在流状态未清除其所有错误的情况下,它将不会运行。这意味着提取到last不执行任何操作,并且它保留了上一个提取(没有std::noskipws的提取)的值,因为流没有清除字符串。


至于使用char的原因:字符在C或C++中没有格式要求。任何和所有字符都可以提取到类型char的对象中,这就是为什么尽管设置了std::noskipws,您仍然看到正确的输出的原因:

27.7.2.2.3/1 [istream::提取器]

template<class charT, class traits>
basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& in,
charT& c);

效果:行为类似于 in 的格式化输入成员(如 27.7.2.2.1 中所述)。构造哨兵对象后,将从in中提取一个字符(如果有),并将其存储在c中。否则,该函数将调用in.setstate(failbit)

提取程序的语义会将字符存储到其操作数中(如果可用)。它不分隔空格(甚至 EOF 字符!它会像普通角色一样提取它。

字符串>>的基本算法是:

1)跳过空格
2)读取并提取直到下一个空格

如果使用noskipws,则first step is skipped.

第一次读取后,您将位于空白处,因此下一次(以及所有后续)读取将立即停止,不提取任何内容。
有关更多信息,您可以看到这一点。

表格 cplusplus.com ,

许多提取操作将空格本身视为终止字符,因此,在禁用 skipws 标志的情况下,某些提取操作可能根本不从流中提取任何字符。
所以,去掉noskipws,当与字符串一起使用时。

原因是在第二个示例中,您根本没有读取最后一个变量,而是打印它的旧值。

std::string first, middle, last;
std::istringstream iss("G B S");
^^^
iss >> first >> middle >> last;
std::cout << "Default behavior: First Name = " << first 
<< ", Middle Name = " << middle << ", Last Name = " << last << 'n';
std::istringstream iss2("G B T");
^^^
iss2 >> std::noskipws >> first >> middle >> last;
std::cout << "noskipws behavior: First Name = " << first 
<< ", Middle Name = " << middle << ", Last Name = " << last << 'n';

默认行为:名字 = G,中间名 = B,姓氏 = S

noskipws 行为:名字 = G,中间名 = ,姓氏 = S

发生这种情况是因为在第二次读取变量后,最后一个流位于空格上。

相关文章:
  • 没有找到相关文章