用C ++演示noskipws

时间:2014-02-16 10:13:53

标签: c++ manipulators

我在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的情况下以这种方式工作。

3 个答案:

答案 0 :(得分:4)

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 :: extractors]

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

效果:行为类似于in中的格式化输入成员(如27.7.2.2.1中所述)。构造一个句子对象后,从in中提取一个字符(如果有的话),并存储在{ {1}}。否则,该函数调用c

提取器的语义将字符存储到其操作数(如果有的话)。它没有界定空格(甚至是EOF字符!)。它会像普通角色一样提取它。

答案 1 :(得分:1)

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

  

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

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

在第一次阅读之后,您将被定位在空白处,因此下一个(以及所有后续)读取将立即停止,不提取任何内容。
有关详细信息,请参阅this

表格cplusplus.com

  

许多提取操作将空格本身视为终止字符,因此,如果禁用了skipws标记,则某些提取操作可​​能不会从流中提取任何字符。
  因此,在使用字符串时删除noskipws。

答案 2 :(得分:0)

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

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

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