我使用<<
流操作符實現了一個對象的反序列化例程。該例程本身使用istreambuf_iterator<char>
來逐個從流中提取字符,以構建該對象。關於`std :: istreambuf_iterator`的使用感到困惑
最終,我的目標是能夠使用istream_iterator<MyObject>
迭代流並將每個對象插入vector
。漂亮的標準,除非我在獲取istream_iterator
到停止遇到碼流結束時迭代。現在,它只是永遠循環播放,即使撥打表示我在文件末尾。
這裏的代碼來重現問題:
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
狀態。調用istream::eof()
返回false,即使返回文件中的最後一個字節,並且istreambuf_iterator<char>(ifs)
與istreambuf_iterator<char>()
相比較,意味着我肯定在流的末尾。
我看着Iostreams庫代碼,看看它究竟是如何確定istream_iterator
是否處於末端位置,基本上它會檢查是否istream::operator void*() const
計算結果爲true
。這istream的庫函數返回:
return this->fail() ? 0 : const_cast<basic_ios*>(this);
換句話說,它返回0
(假)如果failbit設置。然後它將該值與默認構建的實例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)
才能讓循環終止?
循環永久指示流已經變質。問題是爲什麼? – 2010-11-11 01:50:04
@Martin,好吧,即使我用'std :: stringstream'替換文件流,也會發生同樣的問題。所以這不能是某種低級文件相關的問題。 – Channel72 2010-11-11 01:53:57
閱讀@ PigBen的回答。原因是在外層你使用istream_iterator(在for_each)和istreambuf_iterator在內部(operatro >>)。您的使用需要保持一致。在這兩種情況下使用istreambuf_iterators,它應該工作。 – 2010-11-11 18:17:08