Demonstration of noskipws in C++

久未见 提交于 2020-01-06 12:43:27

问题


I was trying out the noskipws manipulator in C++ and I wrote following code.

#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';
}

I expect the following output:

Expected Output

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

Output

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

I modified this code to make it work for chars like this and it works perfectly fine.

#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';
}

I know how cin works and I wasn't able to figure out why it works this way in case of string.


回答1:


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

When an extraction is performed on strings, the string is first cleared and characters are inserted into its buffer.

21.4.8.9 Inserters and extractors

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

Effects: Behaves as a formatted input function (27.7.2.2.1). 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 as if by calling str.append(1, c). [...]

The first read will extract the string "G" into first. For the second extraction, nothing will be extracted because the std::noskipws format flag is set, disabling the clearing of leading whitespace. Because of this, the string is cleared and then the extraction fails because no characters were put in. Here is the continuation of the above clause:

21.4.8.9 Inserters and extractors (Cont.)

[...] Characters are extracted and appended until any of the following occurs:

  • n characters are stored;

  • end-of-file occurs on the input sequence;

  • isspace(c, is.getloc()) is true for the next available input character c.

When the stream determines a failed extraction the std::ios_base::failbit is set in the stream state indicating an error.

From this point on any and all attempts at I/O will fail unless the stream state is cleared. The extractor becomes inoperable and it will not run given a stream state not cleared of all its errors. This means that the extraction into last doesn't do anything and it retains the value it had at the previous extraction (the one without std::noskipws) because the stream did not clear the string.


As for the reason why using char works: Characters have no formatting requirements in C or C++. Any and all characters can be extracted into a object of type char, which is the reason why you're seeing the correct output despite std::noskipws being set:

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);

Effects: Behaves like a formatted input member (as described in 27.7.2.2.1) of in. After a sentry object is constructed a character is extracted from in, if one is available, and stored in c. Otherwise, the function calls in.setstate(failbit).

The semantics for the extractor will store a character into its operand if one is available. It doesn't delimit upon whitespace (or even the EOF character!). It will extract it just like a normal character.




回答2:


The basic algorithm for >> of a string is:

1) skip whitespace
2) read and extract until next whitespace

If you use noskipws, then the first step is skipped.

After the first read, you are positionned on a whitespace, so the next (and all following) reads will stop immediatly, extracting nothing.
For more information you can see this.

Form cplusplus.com ,

many extraction operations consider the whitespaces themselves as the terminating character, therfore, with the skipws flag disabled, some extraction operations may extract no characters at all from the stream.
So , remove the noskipws , when using with strings .




回答3:


The reason is that in the second example you are not reading into last variable at all and instead you are printing old value of it.

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';

Default behavior: First Name = G, Middle Name = B, Last Name = S

noskipws behavior: First Name = G, Middle Name = , Last Name = S

This happen because after second read to variable last stream is positioned on whitespace.



来源:https://stackoverflow.com/questions/21809838/demonstration-of-noskipws-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!