iostateとiostreamのエラー処理

あるプログラムでは、ifstreamとistringstreamを利用している。で、このプログラムをg++とVC++(.NET2003)でビルドして使っている。そこにあるストリームを食べさせたところ、istringstream + VC++の場合のみ不都合が起きた。ios::eof()が拾えないのだ。

while (! ins.eof()) {
  ...
  ins.read(buf, size);
  if (ins.eof()) break;
  ...
}

のようなプログラムは当然のように無限ループに陥った。
はて。
例えば、こう書けば、無限ループには成らない:

while (ins) {
  ...
  ins.read(buf, size);
  if (! ins) break;
  ...
}

…のだけれど、ではこのループからの脱出はEOFによるものなのだろうか、それとも何らかのエラーだろうか?
std::iosにはiostate型の隠れ変数がある。ios::rdstate()で確認できるこの変数は、ストリームの状態を表すビットパターンである。状態としてはios::eofbit, ios::failbit, ios::badbitの3つが定義されている。
FIDSによれば、

badbit
indicates a loss of integrity in an input or output sequence (such as an irrecoverable read error from a file)[入出力シーケンスの完全性の喪失(復旧不能なファイルからの読み込みエラーなど)を示す]
eofbit
indicates that an input operation reached the end of an input sequence[入力操作が入力シーケンスの終端に到達したことを示す]
failbit
indicates that an input operation failed to read the expected characters, or that an output operation failed to generate the desired characters[入力操作が期待された文字の読み込みに失敗したか、あるいは出力操作が要求された文字の生成に失敗したことを示す]

とある。
また、istream::read()については、

Characters are extracted and stored until either of the following occurs:
n characters are stored;
end-of-file occurs on the input sequence (in which case the function calls setstate(failbit|eofbit)
[以下のいずれかがおこるまで文字は展開され、格納される:
n文字が格納された
入力シーケンスの終端に達した(この場合、failbitとeofbitの両方のビットを立てる)]

…つまりistream::read()で!good()であった場合、eofbitとfailbitが両方立つのは仕方ない(というか正しい)ことなのだ。
といことは、結局、最初のコードが無限ループに陥るのは、read()の結果がEOFにならず、単にfail()になった場合である、という事が出来る*1
(続く)

*1:bad()になった場合もあり得るが、今回は考えない