Boost C++ Libraries: Ticket #10422: Counting Iterator return-type causes lifetime issues https://svn.boost.org/trac10/ticket/10422 <p> The counting_iterator upon integers has a dereference member function which is a reference to an integral value held in the iterator. Since an iterator may be destroyed, the reference can be invalid. </p> <p> An example where this occurs was provided by a user of Boost.Range. The application used counting_range with reversed and transformed adaptors. The result was garbage since the reversed dereference member function does *boost::prior(this-&gt;base()); Hence it returns a reference to a temporary iterator that results from the "prior" function. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/10422 Trac 1.4.3 Neil Groves Fri, 29 Aug 2014 17:19:19 GMT <link>https://svn.boost.org/trac10/ticket/10422#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10422#comment:1</guid> <description> <p> As requested by Eric I have included his thoughts on one of the possible solutions: </p> <p> On 8/28/2014 3:49 PM, Neil Groves wrote: </p> <blockquote class="citation"> <p> On 28 August 2014 22:35, Krzysztof Czainski wrote: </p> <blockquote class="citation"> <p> I think the problem is counting_iterator returns a reference to an int it owns. Iterators shouldn't do that. </p> </blockquote> <p> This is exactly what is causing the issue. </p> </blockquote> <p> Right. </p> <blockquote class="citation"> <blockquote class="citation"> <p> Iterators should either: </p> <ul><li>return a reference to something they don't own, or </li><li>return by value. </li></ul></blockquote> <p> Your logic for return type makes a lot of sense. Unfortunately there are conflated requirements upon the return type of dereference operations for the various iterator traversals. See <a href="http://www.boost.org/doc/libs/1_56_0/libs/multi_array/doc/iterator_categories.html">http://www.boost.org/doc/libs/1_56_0/libs/multi_array/doc/iterator_categories.html</a>. </p> </blockquote> <p> I see no conflated requirements. In Boost.Iterators (as opposed to the standard iterator categories), iterator *traversal* deals only with traversal (++, --, +=, -=, etc) and says nothing about the return type of the dereference operation. </p> <p> Krzysztof is right, though. The dereference operation should return an rvalue. That would make the counting_iterator a Readable iterator in the new-style categories. "Readable" is orthogonal to the iterator traversal. </p> <p> So IMO, counting_iterator should be a Readable Iterator and a Random Access Traversal Iterator. When this is mapped to one of the standard iterator categories, it becomes std::input_iterator_tag (because of the requirements on Forward Iterators in the standard). </p> <blockquote class="citation"> <p> I imagine that this is why the counting_iterator is implemented to return a true reference. </p> </blockquote> <p> No, I think this is a bug, plain and simple. Fixing it is likely to cause trouble though. :-( </p> <blockquote class="citation"> <p> This leaves us with rather a thorny problem, a counting_iterator can't have the dereference operator return by value and model the Bidirectional Iterator Concept. Therefore if counting_iterator were to return by value we wouldn't be allowed to reverse (if we constrained ourselves to the Standard iterator traversal categories). It might be that there is room for improvement while working with the Boost traversal tags rather than the iterator traversal tags. </p> </blockquote> <p> If Boost.Range were made aware of the Boost new-style iterator categories -- which make traversal and access independent -- the reversed view could still work with counting_iterator. The resulting view's iterators would also be Random Access Traversal and Readable. </p> <p> Making all of Boost.Range aware of the new-style iterators would be a piece of work, though. </p> <blockquote class="citation"> <p> Thanks for pointing this out, I hadn't spotted this issue with the counting_iterator. After giving this some more thought I shall raise a ticket for Boost.Iterator. </p> </blockquote> <p> Indeed. Please include this discussion in the bug report. </p> <p> Eric </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Neil Groves</dc:creator> <pubDate>Fri, 29 Aug 2014 17:24:14 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10422#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10422#comment:2</guid> <description> <p> My personal view is that we should ensure we have considered alternative solutions since simply making the counting_iterator compliant will: </p> <ol><li>Break existing code without obvious solutions for clients of counting_iterator </li><li>Severely degrade performance of many STL algorithms due to degredation to the input iterator category. </li></ol><p> I think it is worth considering adopting the same solution as has been chosen in Boost.Iterator detail/int_iterator. This returns by value and claims to be a std random_access_iterator. This does potentially practically go wrong if an algorithm uses auto&amp;. I think returning by const value_type would ensure that the lifetime extension works. I believe this only leaves theoretical cases where this would go wrong by classes squirelling away a reference. I don't think this is of practical significance since there are very few assumptions one can make about the lifetime of the reference without knowing about the underlying container/sequence. </p> <p> It is probably worth looking at the experience users have had with int_iterator. </p> </description> <category>Ticket</category> </item> <item> <author>Kohei Takahashi <flast@…></author> <pubDate>Tue, 30 Sep 2014 15:33:22 GMT</pubDate> <title>cc set https://svn.boost.org/trac10/ticket/10422#comment:3 https://svn.boost.org/trac10/ticket/10422#comment:3 <ul> <li><strong>cc</strong> <span class="trac-author">flast@…</span> added </li> </ul> <p> Is this dup of <a class="new ticket" href="https://svn.boost.org/trac10/ticket/2640" title="#2640: Bugs: Legal forward iterators cannot store their referents (was: ... (new)">#2640</a> ? </p> Ticket