Boost Iterator Adaptor, with a mutable member variable is optimized out incorrectly

hello everyone, i am not sure if this is actually a question about boost usage. but in the attached code i'm stuck with the unlikely situation, that gcc optimizes away my code and produces garbage for -On (n>=1), while it works like intended with -O0. attached is the minimal code, with which i could reproduce the problem: on linux i686 g++ version 4.6.3 and x86_64 g++ version 4.7.2, using packaged boost_1_54_0 in both instances, i see the following: when i compile the code with optimization (-O1) % ./iterator_adaptor_weirdness -1219536795 -1219536795 and without (-O0) % ./iterator_adaptor_weirdness 4 2 is this a bug in gcc? is it wrong to use mutable variables in conjunction with iterator_adaptor? any insight is appreciated, jonas P.S.: I know, that this particular instance of the problem, might be better solved using a transform_iterator, but unfortunately that approach doesn't scale.

Your code invokes undefined behaviour. boost::copy() will call code like this in a loop: *out = *in; where 'out' is your ostream iterator and 'in' is a reverse_iterator<B::const_iterator>. reverse_iterator, itself implemented using iterator_adaptor, has an operator* that looks something like this: UnderlyingIterator::reference operator*() { return *boost::prior(base()); } where UnderlyingIterator is B::const_iterator, and thus UnderlyingIterator::reference is 'int const&'. (The boost::prior() call is necessary because reverse_iterator uses iterator_adaptor in such a way that the underlying iterator is one element ahead of the element the reverse_iterator points to. This way, the reversed range's begin() can be the underlying range's end() and vice versa.) Here's the undefined behaviour: boost::prior() returns an iterator by value, which is a temporary in the context of the the reverse_iterator::operator* call. When that iterator is dereferenced in reverse_iterator::operator*, B::const_iterator::operator* returns a reference to a field of this temporary iterator. reverse_iterator::operator* in turn returns this reference. Now when program execution gets to calling the assignment operator in *out = *in; the reverse_iterator::operator* has returned, the temporary B::const_iterator inside it has been destructed, and the returned reference is now dangling. ostream_iterator::operator= tries to read from this dangling reference, and now anything can happen. Given that you're invoking undefined behaviour, it is perfectly normal that an unoptimized build works fine while an optimized build gives incorrect results. To avoid the undefined behaviour, I would recommend making B::const_iterator's reference type be 'int const' (without the reference) - this can be controlled through the fifth template parameter of iterator_adaptor: class const_iterator : public boost::iterator_adaptor<const_iterator, std::vector<int>::const_iterator, int const, boost::bidirectional_traversal_tag, int const> { ... int const dereference() const { return 2 * (*base()); } }; As a general rule, I would avoid writing iterators that return a reference to something stored locally. If you're going to be an lvalue iterator (dereference to a reference), return a reference to something stored externally, otherwise be an rvalue iterator (dereference to a value). Hope that helps. Regards, Nate
participants (2)
-
Jonas Hörsch
-
Nathan Ridge