Проблема в том, что ii_t<>
входной класс итератора из указанного SO-ответа «читает» слишком много элементов, потому что обернутый istream
не возвращает EOF
до разыменованияитератора после того, который возвратил последний элемент в файле.Дополнительный возвращаемый элемент данных повреждает выделенный блок памяти в объекте multi_array
.
Если вы измените класс ii_t<>
на следующий, вы должны получить более совершенное поведение:
template<typename T>
struct ii_t: public iterator<input_iterator_tag, void, void, void, void>
{
ii_t(std::istream& str)
:m_str(&str)
{}
ii_t()
:m_str(NULL)
{}
ii_t& operator++() {return *this;} // increment does nothing.
ii_t& operator++(int){return *this;}
T& operator*()
{
// On the de-reference we actuall read the data into a local //// static ////
// Thus we can return a reference
static T result;
m_str->read(reinterpret_cast<char*>(&result),sizeof(T));
return result;
}
// If either iterator has a NULL pointer then it is the end() of stream iterator.
// Input iterators are only equal if they have read past the end of stream.
bool operator!=(ii_t const& rhs)
{
// we need to make sure we're not just about to hit EOF
// if we already haven't
if (m_str && m_str->good()) {
char dummy;
m_str->read(&dummy,1);
if (m_str->good()) {
m_str->putback(dummy);
}
}
if (rhs.m_str && rhs.m_str->good()) {
char dummy;
rhs.m_str->read(&dummy,1);
if (rhs.m_str->good()) {
rhs.m_str->putback(dummy);
}
}
bool lhsPastEnd = (m_str == NULL) || (!m_str->good());
bool rhsPastEnd = (rhs.m_str == NULL) || (!rhs.m_str->good());
return !(lhsPastEnd && rhsPastEnd);
}
private:
std::istream* m_str;
};
Соответствующие изменения внесены в функцию bool operator!=(ii_t const& rhs)
, где при необходимости выполняется фиктивное чтение (затем отменяется) для обернутого istream
, чтобы определить, находится ли istream в EOF.
Обратите внимание, чтоЯ не утверждаю, что это лучший способ справиться с ситуацией EOF
, но, похоже, он работает.