第八章有個例子,非常簡單,就是讀入使用者輸入,賦給一個int,這裡面有一個判斷,就是如果使用者輸入的不是int,那麼,cin就會變成invalid,裡面就有condition state,於是我們可以catch這個state並clear,然後繼續讀入。
但是書上給的例子有個錯誤,原來的程式是這樣的:
-
Code: Select all
-
#include <iostream>
#include <stdexcept>
using namespace std;int main(int argc, char **argv)
{
int ival;
// cout << "Begin state is: " << cin.rdstate() << endl;
while (cin >> ival, !cin.eof()) {
// cout << "Current Enter loop state is: " << cin.rdstate() << endl;
if (cin.bad()) {
// no catch so the terminate will be called
throw runtime_error("IO Stream corrupted");
}
if (cin.fail()) {
cerr << "bad data, try again: ";
cin.clear(istream::failbit);
// cout << "Current state is: " << cin.rdstate() << endl;
continue;
}
// ok, print out this integer
cout << "Input correct, your number is: " << ival << endl;
}
}
這裡有兩個錯誤:
(1)在Linux,g++環境下,cin.clear(istream::failbit)並不能清除cin的fail狀態,儘管從clear函數的文檔上來看應該是可以的。沒辦法,我改成了cin.clear()就OK了
(2) 遺漏了cin.ignore這個句子或有相同效果的代碼。這是因為cin的fail狀態雖然被消除了,但是本次讀入的錯誤的使用者輸入,比如使用者輸入的是一 個字串,還存在於cin的buffer中,這樣,下次迴圈cin >> ival照樣出錯,於是這樣就形成了死迴圈。因為cin的buffer中始終存在著使用者第一次輸入的錯誤資料,於是while迴圈就一直繼續著。
後 來我加了這樣一句: cin.ignore(100000, '\n'); 就OK了。可以看ignore的文檔,代碼的意思是ignore buffer中從一開始到第一個\n為止的所有字元,第一個參數故意寫的很大,這是因為ignore的第一個參數表示ignore多少個字元,太小會導致 buffer中清除的不乾淨。
修改後的代碼如下:
-
Code: Select all
-
#include <iostream>
#include <stdexcept>
using namespace std;int main(int argc, char **argv)
{
int ival;
// cout << "Begin state is: " << cin.rdstate() << endl;
while (cin >> ival, !cin.eof()) {
// cout << "Current Enter loop state is: " << cin.rdstate() << endl;
if (cin.bad()) {
// no catch so the terminate will be called
throw runtime_error("IO Stream corrupted");
}
if (cin.fail()) {
cerr << "bad data, try again: ";
cin.clear();
// Here cin's error condition state cannot be removed unless
// we use cin.clear() directly
// cin.clear(istream::failbit);
// ignore current read wrong characters otherwise the loop
// will go infinitely
cin.ignore(11111111, '\n');
// cout << "Current state is: " << cin.rdstate() << endl;
continue;
}
// ok, print out this integer
cout << "Input correct, your number is: " << ival << endl;
}
}
順便附上本章的另外一個練習代碼,列印常值內容,使用了fstream:
-
Code: Select all
-
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;int main()
{
ifstream input;
vector<string> filelist;
filelist.push_back("read.cc");
filelist.push_back("fread.cc");
filelist.push_back("dummy.cc");
vector<string>::const_iterator it = filelist.begin();
string s;
// loop begin
while (it != filelist.end()) {
input.open(it->c_str());
if (!input) {
cout << "Open file " << *it << " failed, quit..." << endl;
break;
}
cout << "Printing file " << *it << endl;
while (getline(input, s))
cout << s << endl;
input.close();
input.clear();
++it;
}
}