2014-08-28 23:22 GMT+02:00 Neil Groves <neil@grovescomputing.com>:
On 28 August 2014 20:50, Robert Jones <robertgbjones@gmail.com> wrote:
Can anyone explain why my last output line is garbage?

int main( )
{
    using boost::adaptors::reversed;
    using boost::adaptors::transformed;
    using boost::counting_range;
    using boost::phoenix::arg_names::_1;

    print_it( counting_range( 1, 5 ) );
    print_it( counting_range( 1, 5 ) | reversed );

    print_it( counting_range( 1, 5 ) |            transformed( doubled ) );
    print_it( counting_range( 1, 5 ) | reversed | transformed( doubled ) );

    print_it( counting_range( 1, 5 ) |            transformed( bind( doubled, _1 ) ) );
    print_it( counting_range( 1, 5 ) | reversed | transformed( bind( doubled, _1 ) ) );
}


Same result on VS12 (2013).
 
The counting_range instance is a unnamed temporary, since the adaptors are applied to this temporary the adapted iterators may live beyond the lifetime of the source. If you where to add the line:

const auto& rng = counting_range(1, 5)

and then you did:
print_it(rng | reversed | transformed(bind(doubled, _1)));

it should then work since there are no issues with chaining the adaptors since the iterators are always copied from the base range instances during the chaining process. One has to manage the lifetime of the source to ensure it lives beyond the lifetime of the iterators.


Actually, I get garbage with the above too. I don't think the problem is counting_range being a temporary, because it is guaranteed to outlive the call to print_it() here.

My explanation: dereferencing a reverse_iteraotr(counting_iterator(5)) works like this:
1. make a local copy of counting_iterator(5)
2. decrement the local copy
3. dereference the local copy, which returns a reference
4. return the reference
5. destroy the local copy, laving the returned reference dangling

Regards,
Kris