<<
ストリーム演算子を使用して、オブジェクトの逆シリアル化ルーチンを実装しました。ルーチン自体はistreambuf_iterator<char>
、オブジェクトを構築するために、を使用してストリームから文字を1つずつ抽出します。
最終的に、私の目標は、を使用してストリームを反復処理し、istream_iterator<MyObject>
各オブジェクトをに挿入できるようにすることvector
です。ストリームの終わりに達したときに反復istream_iterator
を停止するのに問題があることを除いて、かなり標準的です。今のところistream::tellg()
、ファイルの最後にいることを示す呼び出しがあったとしても、それは永遠にループします。
問題を再現するためのコードは次のとおりです。
struct Foo
{
Foo() { }
Foo(char a_, char b_) : a(a_), b(b_) { }
char a;
char b;
};
// Output stream operator
std::ostream& operator << (std::ostream& os, const Foo& f)
{
os << f.a << f.b;
return os;
}
// Input stream operator
std::istream& operator >> (std::istream& is, Foo& f)
{
if (is.good())
{
std::istreambuf_iterator<char> it(is);
std::istreambuf_iterator<char> end;
if (it != end) {
f.a = *it++;
f.b = *it++;
}
}
return is;
}
int main()
{
{
std::ofstream ofs("foo.txt");
ofs << Foo('a', 'b') << Foo('c', 'd');
}
std::ifstream ifs("foo.txt");
std::istream_iterator<Foo> it(ifs);
std::istream_iterator<Foo> end;
for (; it != end; ++it) cout << *it << endl; // iterates infinitely
}
この些細な例では、istreambuf_iteratorも必要ないことはわかっていますが、問題を単純化しようとしているだけなので、人々が私の質問に答える可能性が高くなります。
したがって、ここでの問題はistreambuf_iterator
、がストリームバッファの最後に到達しても、実際のストリーム自体が状態にならないことEOF
です。ファイルの最後のバイトを返し、trueと比較しistream::eof()
てもfalseを返すように呼び出します。これは、私が間違いなくストリームの最後にいることを意味します。istream::tellg()
istreambuf_iterator<char>(ifs)
istreambuf_iterator<char>()
istream_iterator
IOstreamsライブラリコードを調べて、が終了位置にあるかどうかを正確に判断する方法を確認しました。基本的には、にistream::operator void*() const
評価されるかどうかを確認しtrue
ます。このistreamライブラリ関数は単に以下を返します。
return this->fail() ? 0 : const_cast<basic_ios*>(this);
0
つまり、フェイルビットが設定されている場合は(false)を返します。次に、この値をのデフォルトで構築されたインスタンスの同じ値と比較istream_iterator
して、最後にいるかどうかを判断します。
そのため、比較が真と終了イテレータを比較std::istream& operator >> (std::istream& is, Foo& f)
するときに、ルーチンでフェイルビットを手動で設定してみました。istreambuf_iterator
これは完全に機能し、ループを適切に終了しました。しかし今、私は本当に混乱しています。「ストリームの終わり」の状態を示すために、istream_iterator
間違いなくチェックしているようです。std::ios::failbit
しかし、それは何std::ios::eofbit
のためではありませんか?failbit
たとえば、の基になるファイルをfstream
開くことができなかった場合など、エラー状態のためだと思いました。
では、なぜistream::setstate(std::ios::failbit)
ループを終了させるために呼び出す必要があるのでしょうか。