Stringstream
两次输入输出,无法正常工作
连续使用stringstream写和读,会出现错误
int main() {
stringstream ss;
string s = "123";
int a;
ss << s;
ss >> a; //123
cout << ss.str() << endl; //123
ss << s; //error
cout << ss.str() << endl; //实际123 预期123123
}
但是,如果在第二次写之前,把stringstream的状态复位,就可以正常执行了,代码如下:
int main() {
stringstream ss;
string s = "123";
int a;
ss << s;
ss >> a; //123
cout << ss.str() << endl; //123
ss.clear();
ss << s;
cout << ss.str() << endl; //123123
}
所以,这跟stringstream在进行读写的时候的状态置位有关了,所以要看看stringstream的读写逻辑。
先上一张stringstream的继承关系图
根据cppreferance,stringstream中>>
的功能是继承自istream
我们来看看istream
的>>
是怎么执行的,对于流输入到数值类型的时候,>>
执行的工作如下
Extracts and parses characters sequentially from the stream to interpret them as the representation of a value of the proper type, which is stored as the value of val.
Internally, the function accesses the input sequence by first constructing a sentry object (with noskipws set tofalse
). Then (if good), it calls num_get::get (using the stream’s selected locale) to perform both the extraction and the parsing operations, adjusting the stream’s internal state flags accordingly. Finally, it destroys the sentry object before returning.----cppreference
简单来说,流输入进行的条件是good
为1,因此,stringstream无法工作的原因是在进行第二次写操作的时候,good
不为1。
那么,我们首先得看看,good是什么
最左边的一列表示iostate(io状态)的各位(因为状态iostate是由四个状态位逻辑或组成),每一位被置位之后,不同的状态确认函数(第三列)就会有不同的返回值,这之中包括了good()函数。
所以,stringstream无法工作的原因就是因为其他状态位(eofbit、failbit或者badbit)被置位了,那什么时候这些状态位会被改变呢?
我们可以看看上表的第二列,它描述了什么时候某一位会被置位。而且,对应的状态确认函数会有不一样的结果。所以,我们可以根据状态确认函数的结果来判断出现了什么情况。
int main() {
stringstream ss;
string s = "123";
int a;
ss << s;
ss >> a;
std::cout << std::boolalpha
<< "\nss.eof() = " << ss.eof()
<< "\nss.good() = " << ss.good()
<< "\nss.bad() = " << ss.bad()
<< "\nss.fail() = " << ss.fail();
}
结果
ss.eof() = true
ss.good() = false
ss.bad() = false
ss.fail() = false
所以,我们可以通过查表得知当前状态位被置位的原因是读到了EOF
(文件结束符)。
那么到这里我们程序的问题就已经解决了,即第二次写无法写的原因是由于第一次读的时候读到了eof
,导致eofbit
位被置位,因而good
函数返回值为false
,导致接下来的流输入无法进行。
但是,为什么平时cin
(实际上是istream的一个实例),但是平时普通使用的时候不会遇到eof
的问题?这是因为,每次cin
的时候都会有一个回车,而cin
到回车就不会继续读下去了,因此读不到EOF
所以也许我们在使用stringstream
的时候应该都带上回车以避免上述问题?
例如:
int main() {
stringstream ss;
string s = "123";
int a;
ss << s << endl;
ss >> a; //123
s += "321";
ss << s;
ss >> a;
cout << a << endl; //123321
}