istream_iterator do unexpected read from stream when initialized by istream&.
It is not required from increment operators of istream_iterator that _M_ok will be true as precondition. --- libstdc++-v3/include/bits/stream_iterator.h | 19 +++++----- .../24_iterators/istream_iterator/81964.cc | 42 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 libstdc++-v3/testsuite/24_iterators/istream_iterator/81964.cc diff --git a/libstdc++-v3/include/bits/stream_iterator.h b/libstdc++-v3/include/bits/stream_iterator.h index f9c6ba6..26959ce 100644 --- a/libstdc++-v3/include/bits/stream_iterator.h +++ b/libstdc++-v3/include/bits/stream_iterator.h @@ -56,8 +56,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: istream_type* _M_stream; - _Tp _M_value; - bool _M_ok; + mutable _Tp _M_value; + mutable bool _M_ok; public: /// Construct end of input stream iterator. @@ -66,8 +66,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Construct start of input stream iterator. istream_iterator(istream_type& __s) - : _M_stream(&__s) - { _M_read(); } + : _M_stream(&__s), _M_value(), _M_ok(false) + { } istream_iterator(const istream_iterator& __obj) : _M_stream(__obj._M_stream), _M_value(__obj._M_value), @@ -77,6 +77,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const _Tp& operator*() const { + if (!_M_ok) { + _M_read(); + } __glibcxx_requires_cond(_M_ok, _M_message(__gnu_debug::__msg_deref_istream) ._M_iterator(*this)); @@ -89,9 +92,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION istream_iterator& operator++() { - __glibcxx_requires_cond(_M_ok, - _M_message(__gnu_debug::__msg_inc_istream) - ._M_iterator(*this)); _M_read(); return *this; } @@ -99,9 +99,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION istream_iterator operator++(int) { - __glibcxx_requires_cond(_M_ok, - _M_message(__gnu_debug::__msg_inc_istream) - ._M_iterator(*this)); istream_iterator __tmp = *this; _M_read(); return __tmp; @@ -113,7 +110,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: void - _M_read() + _M_read() const { _M_ok = (_M_stream && *_M_stream) ? true : false; if (_M_ok) diff --git a/libstdc++-v3/testsuite/24_iterators/istream_iterator/81964.cc b/libstdc++-v3/testsuite/24_iterators/istream_iterator/81964.cc new file mode 100644 index 0000000..f58fc87 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/istream_iterator/81964.cc @@ -0,0 +1,42 @@ +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <sstream> +#include <iterator> +#include <testsuite_hooks.h> + +// libstdc++/81964 +void test0x() +{ + using namespace std; + bool test __attribute__((unused)) = true; + + std::istringstream s("1 2"); + std::istream_iterator<int> ii1(s); + std::istream_iterator<int> ii2(s); + + VERIFY( *ii2 == 1 ); + VERIFY( *ii1 == 2 ); +} + +int main() +{ + test0x(); + return 0; +} -- 2.10.1