私の"+"よ、どこ行った?

標準ライブラリでの"+"と"-"の扱いがおかしい気がする。


cinから数字か文字を読み込みたい、とか思いたったのでコードを書いてみた。

/* バッファども */
int num;
char ch;

using namespace std;
while( cin.good() ) {
	// とりあえず数字として読み込んでみる
	cin >> num;	/* ...(A) */
	if( !cin.fail() ) {
		// 数字として読めたぜ ウヘヘ
		cerr << "num [" << num << "]" << endl;
	} else {
		// だめっぽいので文字として読み込み直す
		// 一旦エラー情報をクリア
		cin.clear();
		// 文字として読む
		cin >> ch;	/* ...(B) */
		cerr << "char[" << ch << "]" << endl;
	}
}

多分こんなでいいはず。


実行してみる。

123
num [123]
123 456
num [123]
num [456]
abc
char[a]
char[b]
char[c]
+123 abc -456
num [123]
char[a]
char[b]
char[c]
num [-456]

すこぶるいい感じ。


で、問題の入力はコチラ。

10 + 10
num [10]
char[1]
num [0]

おいこら、"+"はどこ行った?
というか"1"が"char"ってなんだ?


で、何となく原因判明。
"10 + 10"が入力されたときは

  1. "10"がnumに入れられる(A)
  2. エラーなことは何もないのでfailせず"num [10]"を吐く
  3. 次の入力は"+"(A)
  4. これは数字かもしれない、と思ってみたが実はエラー。
  5. failするので(B)へ
  6. で、本来ならば(A)と(B)では同じものが入力されるはずなので、(B)でも"+"が来るはず
  7. なのだが、なぜか(B)で次の"1"が来る
  8. おかげで"char [1]"と出力されてしまう
  9. 次の入力の"0"はそのまま"num [0]"と出力される(A)

という流れっぽい。(A,Bは↑のソースコードのそれ


(>>)が失敗してもcinのファイルポインタ(?)*1は進まないはず*2、なのだが"+"だと進んでしまうらしい*3
これはバグなのか仕様なのか...。
そもそも↑のソースコードでのcinを使い方が間違ってるのか...。
とりあえずむかついたのでhatenaに書いてみた。

*1:標準ライブラリでもファイルポインタっていうのか?

*2:ちなみにこれをやりたいときはignore()とかを使うといいらしい。

*3:"-"でも同様