Data saved in my file is (white spaces added at both beginning and end on purpose for this test):
1 2 3
Loading the data using the code below with or without "std::ws" does not cause any difference. So I am confused by the role of "std::ws" as I have seen code using it. Can someone explain a little bit? Thanks!
void main ()
{
ifstream inf;
inf.open ("test.txt");
double x=0, y=0, z=0;
string line;
getline(inf, line);
istringstream iss(line);
//Using "std::ws" here does NOT cause any difference
if (!(iss >> std::ws >> x >> y >> z >> std::ws))
{
cout << "Format error in the line" << endl;
}
else
{
cout << x << y << z << endl;
}
iss.str(std::string ());
iss.clear();
cin.get();
}
The primary use of std::ws
is when switching between formatted and unformatted input:
- formatted input, i.e., the usual input operators using `in >> value, skip leading whitespace and stop whenever the format is filled
- unformatted input, e.g.,
std::getline(in, value)
does not skip leading whitespace
For example, when reading an age
and a fullname
you might be tempted to read it like this:
int age(0);
std::string fullname;
if (std::cin >> age && std::getline(std::cin, fullname)) { // BEWARE: this is NOT a Good Idea!
std::cout << "age=" << age << " fullname='" << fullname << "'\n";
}
However, if I'd enter this information using
47
Dietmar Kühl
It would print something like this
age=47 fullname=''
The problem is that the newline following the 47
is still present and immediately fills the std::getine()
request. As a result you'd rather use this statement to read the data
if (std::cin >> age && std::getline(std::cin >> std::ws, fullname)) {
...
}
The use of std::cin >> std::ws
skips the whitespace, in particular the newline, and carries on reading where the actual content is entered.
By default, the stream's skipws
bit is set and whitespace is automatically skipped before each input. If you unset it with iss >> std::noskipws
, then you'll need iss >> std::ws
later.
There are also times when whitespace is not automatically skipped. For example, to detect the end of the input, you can use if ( ( iss >> std::ws ).eof() )
.
skipws and noskipws are sticky but ws is NOT sticky, so if you want to skip whitespaces with ws you must use it before every operator>>.
Also note that skipws and noskipws only apply to formatted input operation performed with operator>> on the stream.
but ws applies to both formatted input operation ( using operator>> ) and unformatted input operation (e.g. get, put, putback , .... )
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main ()
{
char c;
istringstream input( " 1test 2test " );
input >> skipws;
c = input.peek();
//skipws doesn't skip whitespaces in unformatted input
cout << "After using skipws c = " << c << endl;
input >> ws;
c = input.peek();
cout << "After using ws c = " << c << endl;
}
Output:
After using skipws c =
After using ws c = 1