Reputation: 119
Let me make this simple. Why does the program below write "Thi" instead of "Thisisatest."? I expect it to write the first two characters in the first loop, and then write the rest of the test string without whitespace.
#include <sstream>
#include <iostream>
using namespace std;
int main() {
string test = "This is just a test.";
stringstream ss(test);
char c;
int i = 0;
while (ss >> noskipws >> c) {
int ascii = (int)c;
if (i > 2) { // break after writing 2 characters
break;
}
i++;
cout << c;
}
// continue using the same sstring,
// but with a string instead of a char
// notice that there is no noskipws here
string s;
while(ss >> s) {
cout << s;
}
// program exits with only "Thi" printed
return 0;
}
Interestingly enough, removing >> noskipws
fixes the problem. Why though?
Upvotes: 2
Views: 72
Reputation: 2206
ss >> s
means read in string s, and stop when you encounter whitespace.
I added a pair of extra output statements to your program, one at the end of each loop. After the first loop ends, the input stream is positioned to input a space as its next character.
When the program tries to input string s, it encounters whitespace immediately, and because you configured the stream to not skip leading whitespace, it stops, failing to input string s. That failure causes the stream to be put into a failed state.
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
int main() {
string test = "This is just a test.";
stringstream ss(test);
char c;
int i = 0;
while (ss >> noskipws >> c) {
int ascii = (int)c;
if (i > 2) { // break after writing 2 characters
break;
}
i++;
cout << c;
}
std::cout << boolalpha
<< "\nAfter first loop: "
<< "\n ss.fail() : " << ss.fail()
<< "\n c : \'" << c << '\''
<< "\n";
// continue using the same sstring,
// but with a string instead of a char
// notice that there is no noskipws here
string s{ "value before ss >> s" };
while (ss >> s) {
cout << s;
}
std::cout << "\nAfter second loop: "
<< "\n ss.fail() : " << ss.fail()
<< "\n s : \"" << s << '\"'
<< '\n';
// program exits with only "Thi" printed
return 0;
}
Here is the output:
Thi
After first loop:
ss.fail() : false
c : 's'
After second loop:
ss.fail() : true
s : ""
Upvotes: 1
Reputation: 39084
The reduced code (the first loop reads 4 characters and exits before printing the 4th one):
#include <sstream>
#include <iostream>
using namespace std;
int main() {
string test = " is just a test.";
stringstream ss(test);
ss >> noskipws;
string s;
while(ss >> s) {
cout << s;
}
cout << ss.fail();
}
// Output: 1.
The extracting to a string has a contract:
Characters are extracted and appended until any of the following occurs:
- end-of-file occurs on the input sequence;
isspace(c, is.getloc())
is true for the next available input characterc
.If no characters are extracted then
std::ios::failbit
is set on a stream.
ss >> s
job is str.erase()
then str.append(1, c)
for each read c
above. isspace(c, is.getloc())
is true on the first character - nothing is extracted, s
is empty, the stream ss
is set to the fail state.
Upvotes: 0