
There seems to be a bug in the string algorithm library that results in a valid container iterator being compared to a "singular" default constructed iterator: this operation is not supported by the iterator requirements and results in an assertion being thrown when testing with VC7.1+STLPort (or any other compiler with STLPort for that matter). The call stack is: stlport_vc71_stldebug46.dll!_STL::__stl_debug_engine<bool>::_Terminate() Line 324 C++ stlport_vc71_stldebug46.dll!_STL::__stl_debug_engine<bool>::_Assert(const char * __expr=0x0057420c, const char * __f=0x00574180, int __l=0x0000012d) Line 308 C++ regex_test.exe!_STL::operator==<_STL::_Nondebug_string<char,_STL::char_trait s<char>,_STL::allocator<char> > >(const _STL::_DBG_iter_base<_STL::_Nondebug_string<char,_STL::char_traits<char>,_ST L::allocator<char> > > & __x={...}, const _STL::_DBG_iter_base<_STL::_Nondebug_string<char,_STL::char_traits<char>,_ST L::allocator<char> > > & __y={...}) Line 301 + 0x2e C++ regex_test.exe!boost::algorithm::iterator_range<_STL::_DBG_iter<_STL::_Nonde bug_string<char,_STL::char_traits<char>,_STL::allocator<char>
,_STL::_Const_traits<char> > ::operator==<_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits< char>,_STL::allocator<char> >,_STL::_Const_traits<char> > >() Line 119 + 0x47 C++
regex_test.exe!boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondeb ug_string<char,_STL::char_traits<char>,_STL::allocator<char>
,_STL::_Const_traits<char> > >::equal(const boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<char, _STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char> > & Other={...}) Line 147 + 0x12 C++
regex_test.exe!boost::iterator_core_access::equal<boost::algorithm::find_ite rator<_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_S TL::allocator<char> >,_STL::_Const_traits<char> >
,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
() Line 518 C++
regex_test.exe!boost::operator==<boost::algorithm::find_iterator<_STL::_DBG_ iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL::allocator<cha r> >,_STL::_Const_traits<char> >
,boost::algorithm::iterator_range<_STL::_DBG_iter<_STL::_Nondebug_string<ch ar,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
const ,boost::forward_traversal_tag,boost::algorithm::iterator_range<_STL::_DBG_it er<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL::allocator<char> ,_STL::_Const_traits<char> > > const &,int,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string <char,_STL::char_traits<char>,_STL::allocator<char> ,_STL::_Const_traits<char> > ,boost::algorithm::iterator_range<_STL::_DBG_iter<_STL::_Nondebug_string<ch ar,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char> const ,boost::forward_traversal_tag,boost::algorithm::iterator_range<_STL::_DBG_it er<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL::allocator<char> ,_STL::_Const_traits<char> > > const &,int>(const boost::iterator_facade<boost::algorithm::find_iterator<_STL::_DBG_iter<_STL: :_Nondebug_string<char,_STL::char_traits<char>,_STL::allocator<char> ,_STL::_Const_traits<char> > ,boost::algorithm::iterator_range<_STL::_DBG_iter<_STL::_Nondebug_string<ch ar,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char> const ,boost::forward_traversal_tag,boost::algorithm::iterator_range<_STL::_DBG_it er<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL::allocator<char> ,_STL::_Const_traits<char> > > const &,int> & lhs={...}, const boost::iterator_facade<boost::algorithm::find_iterator<_STL::_DBG_iter<_STL: :_Nondebug_string<char,_STL::char_traits<char>,_STL::allocator<char> ,_STL::_Const_traits<char> > ,boost::algorithm::iterator_range<_STL::_DBG_iter<_STL::_Nondebug_string<ch ar,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char> const ,boost::forward_traversal_tag,boost::algorithm::iterator_range<_STL::_DBG_it er<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL::allocator<char> ,_STL::_Const_traits<char> > > const &,int> & rhs={...}) Line 819 + 0x32 C++
regex_test.exe!boost::iterator_adaptor<boost::transform_iterator<boost::algo rithm::detail::copy_iterator_rangeF<_STL::basic_string<char,_STL::char_trait s<char>,_STL::allocator<char>
,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default>,boost::algorithm::find_iterator<_ST L::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL::alloc ator<char> >,_STL::_Const_traits<char> > ,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> ,boost::use_default,_STL::basic_string<char,_STL::char_traits<char>,_STL::a llocator<char> ,boost::use_default>::equal<boost::transform_iterator<boost::algorithm::det ail::copy_iterator_rangeF<_STL::basic_string<char,_STL::char_traits<char>,_S TL::allocator<char> ,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default>,boost::algorithm::find_iterator<_ST L::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL::alloc ator<char> >,_STL::_Const_traits<char> > ,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> ,boost::use_default,_STL::basic_string<char,_STL::char_traits<char>,_STL::a llocator<char> >,boost::use_default>() Line 297 + 0x12 C++
regex_test.exe!boost::iterator_core_access::equal<boost::transform_iterator< boost::algorithm::detail::copy_iterator_rangeF<_STL::basic_string<char,_STL: :char_traits<char>,_STL::allocator<char>
,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default>,boost::transform_iterator<boost::al gorithm::detail::copy_iterator_rangeF<_STL::basic_string<char,_STL::char_tra its<char>,_STL::allocator<char> ,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default> >() Line 518 C++
,_STL::allocator<char> ,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default>,_STL::basic_string<char,_STL::char_
,boost::forward_traversal_tag,_STL::basic_string<char,_STL::char_traits<cha r>,_STL::allocator<char> ,int,boost::transform_iterator<boost::algorithm::detail::copy_iterator_rang eF<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> ,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default>,_STL::basic_string<char,_STL::char_
,boost::forward_traversal_tag,_STL::basic_string<char,_STL::char_traits<cha r>,_STL::allocator<char> >,int>(const boost::iterator_facade<boost::transform_iterator<boost::algorithm::detail::c opy_iterator_rangeF<_STL::basic_string<char,_STL::char_traits<char>,_STL::al locator<char> ,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default>,_STL::basic_string<char,_STL::char_
,boost::forward_traversal_tag,_STL::basic_string<char,_STL::char_traits<cha r>,_STL::allocator<char> >,int> & lhs={...}, const boost::iterator_facade<boost::transform_iterator<boost::algorithm::detail::c opy_iterator_rangeF<_STL::basic_string<char,_STL::char_traits<char>,_STL::al locator<char> ,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default>,_STL::basic_string<char,_STL::char_
regex_test.exe!boost::operator!=<boost::transform_iterator<boost::algorithm: :detail::copy_iterator_rangeF<_STL::basic_string<char,_STL::char_traits<char traits<char>,_STL::allocator<char> traits<char>,_STL::allocator<char> traits<char>,_STL::allocator<char> traits<char>,_STL::allocator<char>
,boost::forward_traversal_tag,_STL::basic_string<char,_STL::char_traits<cha r>,_STL::allocator<char> >,int> & rhs={...}) Line 820 + 0x32 C++
regex_test.exe!_STL::__vector<_STL::basic_string<char,_STL::char_traits<char
,_STL::allocator<char> ,_STL::allocator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> > > ::_M_range_initialize<boost::transform_iterator<boost::algorithm::detail::c opy_iterator_rangeF<_STL::basic_string<char,_STL::char_traits<char>,_STL::al locator<char> ,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default> >() Line 535 + 0x17 C++
regex_test.exe!_STL::__vector<_STL::basic_string<char,_STL::char_traits<char
,_STL::allocator<char> ,_STL::allocator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> > > ::_M_initialize_aux<boost::transform_iterator<boost::algorithm::detail::cop y_iterator_rangeF<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> ,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default> >() Line 231 C++
regex_test.exe!_STL::__vector<_STL::basic_string<char,_STL::char_traits<char
,_STL::allocator<char> ,_STL::allocator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> > > ::__vector<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator< char> ,_STL::allocator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> > > <boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<_ STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> ,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default> >() Line 248 C++
regex_test.exe!_STL::vector<_STL::basic_string<char,_STL::char_traits<char>, _STL::allocator<char>
,_STL::allocator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> > > ::vector<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<ch ar> ,_STL::allocator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> > > <boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<_ STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> ,_STL::_DBG_iter<_STL::_Nondebug_string<char,_STL::char_traits<char>,_STL:: allocator<char> >,_STL::_Const_traits<char> > ,boost::algorithm::find_iterator<_STL::_DBG_iter<_STL::_Nondebug_string<cha r,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Const_traits<char>
,boost::use_default,boost::use_default> >() Line 164 + 0x93 C++
regex_test.exe!boost::algorithm::iter_find<_STL::vector<_STL::basic_string<c har,_STL::char_traits<char>,_STL::allocator<char>
,_STL::allocator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> > > ,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > const ,boost::algorithm::detail::find_regexF<boost::reg_expression<char,boost::reg ex_traits<char>,_STL::allocator<char> > > (_STL::vector<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocat or<char> ,_STL::allocator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> > > > & Result={...}, const _STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > & Input={...}, boost::algorithm::detail::find_regexF<boost::reg_expression<char,boost::rege x_traits<char>,_STL::allocator<char> > > Finder={...}) Line 97 + 0x7e C++
regex_test.exe!boost::algorithm::find_all_regex<_STL::vector<_STL::basic_str ing<char,_STL::char_traits<char>,_STL::allocator<char>
,_STL::allocator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> > > ,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> ,char,boost::regex_traits<char>,_STL::allocator<char> (_STL::vector<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocat or<char> ,_STL::allocator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allo cator<char> > > > & Result={...}, const _STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > & Input={...}, const boost::reg_expression<char,boost::regex_traits<char>,_STL::allocator<char> > & Rx={...}, boost::regex_constants::_match_flags Flags=match_default) Line 429 + 0x2b C++ regex_test.exe!find_test() Line 68 + 0x16 C++ regex_test.exe!test_main(int __formal=0x00000001, int __formal=0x00000001) Line 134 C++ regex_test.exe!`anonymous namespace'::call_test_main() Line 37 + 0x12 C++ regex_test.exe!boost::unit_test::function_test_case::do_run() Line 138 + 0x2b C++ regex_test.exe!boost::unit_test::ut_detail::unit_test_monitor::function() Line 77 + 0x14 C++ regex_test.exe!boost::execution_monitor::run_function() Line 188 + 0x54 C++ regex_test.exe!boost::detail::catch_signals(boost::execution_monitor & exmon={...}, bool __formal=true, bool __formal=true) Line 472 C++ regex_test.exe!boost::execution_monitor::execute(bool catch_system_errors=true, int timeout=0x00000000) Line 211 + 0x11 C++
regex_test.exe!boost::unit_test::ut_detail::unit_test_monitor::execute_and_t ranslate(boost::unit_test::test_case * target_test_case=0x009c9990, void (void)* f=0x0047d339, int timeout=0x00000000) Line 43 + 0x13 C++ regex_test.exe!boost::unit_test::test_case::run() Line 145 + 0x6c C++ regex_test.exe!main(int argc=0x00000001, char * * argv=0x009c6bb8) Line 83 C++ And the actual problem I think is caused by (iter_find.hpp#98): transform_iter_type itBegin= make_transform_iterator( find_iterator_type( begin(Input), InputEnd, Finder ), copy_range_type()); transform_iter_type itEnd= make_transform_iterator( find_iterator_type(), // end iterator is default constructed here!! copy_range_type()); SequenceSequenceT Tmp(itBegin, itEnd); // assertion here There may be other occurances of course, this is just the first assertion to be triggered... John.

John Maddock wrote:
There seems to be a bug in the string algorithm library that results in a valid container iterator being compared to a "singular" default constructed iterator: this operation is not supported by the iterator requirements
I'm not sure if I understand correctly what you mean, but the default constructed iterator is inteded to represent the past-the-end value.
And the actual problem I think is caused by (iter_find.hpp#98):
transform_iter_type itBegin=
make_transform_iterator(
find_iterator_type( begin(Input), InputEnd, Finder ),
copy_range_type());
transform_iter_type itEnd=
make_transform_iterator(
find_iterator_type(), // end iterator is default constructed here!!
copy_range_type());
SequenceSequenceT Tmp(itBegin, itEnd); // assertion here
I didn't find out yet what it is (it takes some time to get STLPort running...), but it works for c strings and crashes for std::string (see the first two calls of the library in the split testcase). These and other lines were changed a few days ago to fix a bug that we found on default constructed iterators for c strings. Now it seems there are also troubles with std::strings... The problem is that Pavol left for vacation.
There may be other occurances of course,
Yes, one a few lines below (iter_split) but not more. Stefan

Stefan Slapeta wrote: I think I just wrote down the logic reason for the bug:
I'm not sure if I understand correctly what you mean, but the default constructed iterator is inteded to represent the past-the-end value.
When two iterators are compared, STLPort (in debug mode) checks if they have the same 'owner'. Of course, this owner can never be set for an iterator which behaves like above. Any solution which doesn't break the syntax? I don't have any idea which could be implemented easily... Stefan

Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
Stefan Slapeta wrote:
I think I just wrote down the logic reason for the bug:
I'm not sure if I understand correctly what you mean, but the default constructed iterator is inteded to represent the past-the-end value.
When two iterators are compared, STLPort (in debug mode) checks if they have the same 'owner'. Of course, this owner can never be set for an iterator which behaves like above.
If STLPort is complaining about that, it's because what you're doing is illegal. A default constructed standard container iterator is "singular", and no operations on it (including comparison) are legal other than assigning a non-singular iterator value into it. Although a few specialized iterators in std:: work differently (e.g. istream_iterator), in general you have to make the same assumption for any other iterator.
Any solution which doesn't break the syntax? I don't have any idea which could be implemented easily...
Post some more detail about what you mean by "the syntax" please. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
If STLPort is complaining about that, it's because what you're doing is illegal. A default constructed standard container iterator is "singular", and no operations on it (including comparison) are legal other than assigning a non-singular iterator value into it. Although a few specialized iterators in std:: work differently (e.g. istream_iterator), in general you have to make the same assumption for any other iterator.
I know that but I don't know if Pavol was aware of it. The directory_iterator in the filesystem library also has the same behaviour if default constructed and [although it's no iterator on a standard container and can't cause any assertions in STLPort therefore] the filesystem documentation reads: 'Class directory_iterator provides a C++ standard conforming input iterator ...'.
Any solution which doesn't break the syntax? I don't have any idea which could be implemented easily...
Post some more detail about what you mean by "the syntax" please.
I meant not changing the library interface but maybe this behaviour of default constructed iterators _has_ to be removed. I will try to find all these occurences later. Stefan

Stefan Slapeta wrote:
David Abrahams wrote:
If STLPort is complaining about that, it's because what you're doing is illegal. A default constructed standard container iterator is "singular", and no operations on it (including comparison) are legal other than assigning a non-singular iterator value into it. Although a few specialized iterators in std:: work differently (e.g. istream_iterator), in general you have to make the same assumption for any other iterator.
Very strange: the behaviour that the default constructor equals the past-the-end value is used for the example but it's not even documented for the find iterator! See the example: http://tinyurl.com/4vzlm typedef find_iterator<string::iterator> string_find_iterator; for(string_find_iterator It= make_find_iterator(str1, first_finder("abc", is_iequal())); It!=string_find_iterator(); ++It) ... See the find iterator documentation: http://tinyurl.com/53j5x
find_iterator(); Default constructor.
Construct null iterator. All null iterators are equal. Postconditions: eof()==true << The example above implies that a find iterator which points to the last element will become a 'null iterator' after incrementation. (However, I didn't find this statement anywhere in the documentation) Thus, fixing this bug would not only mean to provide a second function like 'make_find_iterator_end(collection)' that returns a proper end iterator but also to change the behaviour of iterators for incrementation to the past-the-end value etc.! I would really like to hear what Pavol says about that... Stefan

On Mon, Jul 19, 2004 at 11:50:57AM +0200, Stefan Slapeta wrote:
Stefan Slapeta wrote:
David Abrahams wrote:
If STLPort is complaining about that, it's because what you're doing is illegal. A default constructed standard container iterator is "singular", and no operations on it (including comparison) are legal other than assigning a non-singular iterator value into it. Although a few specialized iterators in std:: work differently (e.g. istream_iterator), in general you have to make the same assumption for any other iterator.
Very strange: the behaviour that the default constructor equals the past-the-end value is used for the example but it's not even documented for the find iterator!
See the example: http://tinyurl.com/4vzlm
typedef find_iterator<string::iterator> string_find_iterator; for(string_find_iterator It= make_find_iterator(str1, first_finder("abc", is_iequal())); It!=string_find_iterator(); ++It) ...
See the find iterator documentation: http://tinyurl.com/53j5x
find_iterator(); Default constructor.
Construct null iterator. All null iterators are equal.
Postconditions: eof()==true <<
The example above implies that a find iterator which points to the last element will become a 'null iterator' after incrementation. (However, I didn't find this statement anywhere in the documentation)
Thus, fixing this bug would not only mean to provide a second function like 'make_find_iterator_end(collection)' that returns a proper end iterator but also to change the behaviour of iterators for incrementation to the past-the-end value etc.!
I would really like to hear what Pavol says about that...
As I said in the other post, you are right. There is no need for an extra make_find_iterator_end(...) functions. Current logic is correct, unfortunately, there was a bug in the equal function that caused the problems. Singular iterators should realy not be compared. In addtions, I owe to explicitly say in the documentation, that null iterator acts as the end-of-iteration tag. Best regards, Pavol

Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
David Abrahams wrote:
If STLPort is complaining about that, it's because what you're doing is illegal. A default constructed standard container iterator is "singular", and no operations on it (including comparison) are legal other than assigning a non-singular iterator value into it. Although a few specialized iterators in std:: work differently (e.g. istream_iterator), in general you have to make the same assumption for any other iterator.
I know that but I don't know if Pavol was aware of it. The directory_iterator in the filesystem library also has the same behaviour if default constructed
Not AFAICT, it doesn't!
and [although it's no iterator on a standard container and can't cause any assertions in STLPort therefore] the filesystem documentation reads: 'Class directory_iterator provides a C++ standard conforming input iterator ...'.
As well it is. Conforming iterators are not required to be problematic when default-constructed. See istream_iterator.
Any solution which doesn't break the syntax? I don't have any idea which could be implemented easily... Post some more detail about what you mean by "the syntax" please.
I meant not changing the library interface but maybe this behaviour of default constructed iterators _has_ to be removed. I will try to find all these occurences later.
No it does not, but it may cost you an extra bool in your iterator class. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
No it does not, but it may cost you an extra bool in your iterator class.
Not necessary. Could anybody comment this fix (...and apply it if it's ok)? Tests are fine. BTW, the replace test doesn't compile at all with VC7.1+STLPort. I'll have a look on that later. Stefan --- find_iterator.hpp 15 Jul 2004 21:48:25 -0000 1.8 +++ find_iterator.hpp 19 Jul 2004 14:41:19 -0000 @@ -136,14 +136,10 @@ // comparison bool equal( const find_iterator& Other ) const { - return + return eof() || Other.eof() ? eof() == Other.eof() : ( m_Match==Other.m_Match && m_End==Other.m_End - ) - || - ( - eof() && Other.eof() ); } @@ -301,15 +297,11 @@ // comparison bool equal( const split_iterator& Other ) const { - return + return eof() || Other.eof() ? eof() == Other.eof() : ( m_Match==Other.m_Match && m_Next==Other.m_Next && m_End==Other.m_End - ) - || - ( - eof() && Other.eof() ); }

Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
David Abrahams wrote:
No it does not, but it may cost you an extra bool in your iterator class.
Not necessary. Could anybody comment this fix (...and apply it if it's ok)? Tests are fine.
I don't know what the original code is and I don't want to have to try to piece them together, so it would help if you'd just post what you believe to be a conforming iterator. That said...
BTW, the replace test doesn't compile at all with VC7.1+STLPort. I'll have a look on that later.
Stefan
--- find_iterator.hpp 15 Jul 2004 21:48:25 -0000 1.8 +++ find_iterator.hpp 19 Jul 2004 14:41:19 -0000 @@ -136,14 +136,10 @@ // comparison bool equal( const find_iterator& Other ) const { - return + return eof() || Other.eof() ? eof() == Other.eof() : ( m_Match==Other.m_Match && m_End==Other.m_End - ) - || - ( - eof() && Other.eof() );
This appears to be a complicated way to write: return eof() && Other.eof() || m_Match==Other.m_Match && m_End==Other.m_End; Somehow that seems unlikely to be correct. Are m_Match and m_End valid when eof() is true? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
I don't know what the original code is and I don't want to have to try to piece them together, so it would help if you'd just post what you believe to be a conforming iterator. That said...
Sorry. I'll try to give a short explanation which I hope is sufficient. See again: http://tinyurl.com/53j5x
find_iterator(); Default constructor.
Construct null iterator. All null iterators are equal. Postconditions: eof()==true << What you wanted to know is: the original code was comparing the content of the iterators _before_ comparing the eof states, which is not correct (see below). That said [ ... :) ]
This appears to be a complicated way to write:
return eof() && Other.eof() || m_Match==Other.m_Match && m_End==Other.m_End;
No. Just interpret boolean expressions the way they want to talk to you :) (rationale: see below again)
Somehow that seems unlikely to be correct. Are m_Match and m_End valid when eof() is true?
They are only valid if _both_ eof()'s are false (see documentation above)! m_Match and m_End must not be compared if _one_ of the iterators is in eof (= past-the-end _and_ uninitialized) state. I hope I could make it clear. Stefan

Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
<<
What you wanted to know is: the original code was comparing the content of the iterators _before_ comparing the eof states, which is not correct (see below). That said [ ... :) ]
This appears to be a complicated way to write: return eof() && Other.eof() || m_Match==Other.m_Match && m_End==Other.m_End;
No. Just interpret boolean expressions the way they want to talk to you :)
Lyrical, but I have no clue what it means. Whoops, OK, my boolean inferometer was on the fritz. Your logic looks OK to me. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
Not necessary. Could anybody comment this fix (...and apply it if it's ok)? Tests are fine. BTW, the replace test doesn't compile at all with VC7.1+STLPort. I'll have a look on that later.
Stefan
Applied, thanks. Please post patches as attachments in future.
--- find_iterator.hpp 15 Jul 2004 21:48:25 -0000 1.8 +++ find_iterator.hpp 19 Jul 2004 14:41:19 -0000 @@ -136,14 +136,10 @@ // comparison bool equal( const find_iterator& Other ) const { - return + return eof() || Other.eof() ? eof() == Other.eof() : ( m_Match==Other.m_Match && m_End==Other.m_End - ) - || - ( - eof() && Other.eof() ); }
@@ -301,15 +297,11 @@ // comparison bool equal( const split_iterator& Other ) const { - return + return eof() || Other.eof() ? eof() == Other.eof() : ( m_Match==Other.m_Match && m_Next==Other.m_Next && m_End==Other.m_End - ) - || - ( - eof() && Other.eof() ); }
-- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Hi, On Mon, Jul 19, 2004 at 05:04:32PM +0200, Stefan Slapeta wrote:
David Abrahams wrote:
No it does not, but it may cost you an extra bool in your iterator class.
Not necessary. Could anybody comment this fix (...and apply it if it's ok)? Tests are fine.
This fix is correct. It is precisely what is equal ment to be. I have overlooked the order of comparisons. find_iterator can be in two states: 1) Valid: all internal iterator variables point to valid iterators. Valid find iterators are equal if they point to the same part of the sequence. 2) Null: all null iterators are equal and at the end of sequence, the iterator automaticaly becames null.
BTW, the replace test doesn't compile at all with VC7.1+STLPort. I'll have a look on that later.
I don't know what can be the problem. Can you elaborate a little more? Thanks for the fix, Regards, Pavol

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Pavol Droba
This fix is correct. It is precisely what is equal ment to be. I have overlooked the order of comparisons.
An optimization: I realized later that it can be costly to evaluate the eof states. I would save them in a local bool variable instead of calling the eof functions twice for each comparison. ...return eof() || Other.eof() ? eof() == Other.eof() : etc.
find_iterator can be in two states: 1) Valid: all internal iterator variables point to valid iterators. Valid find iterators are equal if they point to the same part of the sequence.
2) Null: all null iterators are equal and at the end of sequence, the iterator automaticaly becames null.
After my very first (speculative) posting, I found that in the documentation and understood that you don't need any special function for end iterators :)
BTW, the replace test doesn't compile at all with VC7.1+STLPort. I'll have a look on that later.
I don't know what can be the problem. Can you elaborate a little more?
I didn't investigate more then; today it compiles (I really don't understand why, I have to admit) _but_: now the same VC 8 regression test fails with exactly the same error (see below)! (A workaround was to split the function into some smaller ones.) ..\libs\algorithm\string\test\replace_test.cpp(147) : fatal error C1509: compiler limit : too many exception handler states in function 'replace_test'. simplify function Stefan

Hi On Thu, Jul 29, 2004 at 10:58:14PM +0200, Stefan Slapeta wrote:
An optimization: I realized later that it can be costly to evaluate the eof states. I would save them in a local bool variable instead of calling the eof functions twice for each comparison.
...return eof() || Other.eof() ? eof() == Other.eof() : etc.
Thats true ... applied.
I didn't investigate more then; today it compiles (I really don't understand why, I have to admit) _but_: now the same VC 8 regression test fails with exactly the same error (see below)! (A workaround was to split the function into some smaller ones.)
..\libs\algorithm\string\test\replace_test.cpp(147) : fatal error C1509: compiler limit : too many exception handler states in function 'replace_test'. simplify function
I have splited the replace_test() function into smaller chunks. Let's see if it helps. Regards. Pavol

Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
David Abrahams wrote:
If STLPort is complaining about that, it's because what you're doing is illegal. A default constructed standard container iterator is "singular", and no operations on it (including comparison) are legal other than assigning a non-singular iterator value into it. Although a few specialized iterators in std:: work differently (e.g. istream_iterator), in general you have to make the same assumption for any other iterator.
I know that but I don't know if Pavol was aware of it. The directory_iterator in the filesystem library also has the same behaviour if default constructed
Not AFAICT, it doesn't!
and [although it's no iterator on a standard container and can't cause any assertions in STLPort therefore] the filesystem documentation reads: 'Class directory_iterator provides a C++ standard conforming input iterator ...'.
As well it is. Conforming iterators are not required to be problematic when default-constructed. See istream_iterator.
Any solution which doesn't break the syntax? I don't have any idea which could be implemented easily... Post some more detail about what you mean by "the syntax" please.
I meant not changing the library interface but maybe this behaviour of default constructed iterators _has_ to be removed. I will try to find all these occurences later.
No it does not, but it may cost you an extra bool in your iterator class. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

I didn't find out yet what it is (it takes some time to get STLPort running...), but it works for c strings and crashes for std::string (see the first two calls of the library in the split testcase). These and other lines were changed a few days ago to fix a bug that we found on default constructed iterators for c strings. Now it seems there are also troubles with std::strings...
Let me try and be clearer: A singular iterator (that is to say one that is default constructed) has only one behaviour defined for it - you can assign to it a new value - and that's all you can do with it. You cannot compare a singular iterator with another iterator (not even another singular one), *unless* the particular iterator type has some implementation-defined behaviour specified for that particular type. For example the following is not legal code: template <class Iterator> foo(Iterator t) { Iterator a, b; a == b; // illegal operation. a == t; // also illegal. } Sorry! John.

"John Maddock" <john@johnmaddock.co.uk> writes:
You cannot compare a singular iterator with another iterator (not even another singular one), *unless* the particular iterator type has some implementation-defined behaviour specified for that particular type.
Nit: there are no exceptions for singular iterators. In the case you're describing, the iterator is simply not singular. There's no rule that says a default-constructed iterator must be singular. Cheers, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Nit: there are no exceptions for singular iterators. In the case you're describing, the iterator is simply not singular. There's no rule that says a default-constructed iterator must be singular.
Nice. In your last message you wrote:
A default constructed standard container iterator is "singular" <<
So my conclusion is: find_iterator as well as directory_iterator are no iterators on standard containers and therefore there is no requirement to declare them "singular" if they are default constructed. Did I get it right? The problem was that Pavol compared an uninitialized iterator of std::string internally _before_ checking its validity. BTW, I'm on the way to run the complete regressions for Intel 8 + STLPort. David, you didn't apply the patch, did you? Stefan

Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
David Abrahams wrote:
Nit: there are no exceptions for singular iterators. In the case you're describing, the iterator is simply not singular. There's no rule that says a default-constructed iterator must be singular.
Nice. In your last message you wrote:
A default constructed standard container iterator is "singular" <<
So my conclusion is: find_iterator as well as directory_iterator are no iterators on standard containers and therefore there is no requirement to declare them "singular" if they are default constructed. Did I get it right?
Correct. People sometimes make the mistake of writing iterator adaptors that don't respect the potential singularity of their iterator parameters, but that's a different issue.
The problem was that Pavol compared an uninitialized iterator of std::string internally _before_ checking its validity.
BTW, I'm on the way to run the complete regressions for Intel 8 + STLPort.
David, you didn't apply the patch, did you?
I did not apply any patches to anyone else's library. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
David Abrahams wrote:
Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
David, you didn't apply the patch, did you?
I did not apply any patches to anyone else's library.
OK. Anyway, I personally don't use STLPort at the moment, so it's not really important for me.
Who is the library author? That's who should apply the fix. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
participants (5)
-
David Abrahams
-
John Maddock
-
Pavol Droba
-
Stefan Slapeta
-
Stefan Slapeta