On Sat, Apr 28, 2012 at 7:10 AM, tolik levchik <endight@gmail.com> wrote:
The following code gives me segfault. But if `foo_ptr` is `foo*` it works fine.

    #include <vector>
    #include <boost/range/adaptor/indirected.hpp>
    #include <boost/range/adaptor/transformed.hpp>
    #include <boost/range/algorithm/for_each.hpp>
    #include <boost/bind.hpp>
    #include <boost/shared_ptr.hpp>

    struct foo{
        foo(int _i):
            i(_i){}
        virtual void bar() const{
             std::cout << "foo::bar::i " << i << std::endl;
        }
        int i;
    };

    typedef boost::shared_ptr<foo> foo_ptr;
    //typedef foo* foo_ptr;
    foo_ptr trasform(int i){
        return foo_ptr(new foo(i));
    }
    int main(){
        std::vector<int> vec;
        vec.push_back(1);

        using namespace boost::adaptors; using boost::bind;
        boost::for_each(vec
                        | transformed(bind(&trasform, _1))
                        | indirected,
     bind(&foo::bar, _1));
    }
Is it expected behavior of adaptors ?

I think so. Here's my guess what's going on. Consider what the dereference function might look like for an iterator to the range

vec | transformed(bind(&transform, _1)) |  indirected

foo& dereference()
{
    int& i = *vec_it; // dereference iterator to vec
    foo_ptr = transform(i); // pass i through bind(&transform, _1)
    foo& x = *foo_ptr; // pass foo_ptr through indirected
    return x;
}

Sadly, the only foo_ptr "backing" the foo& goes out of scope once the foo& is returned, so that foo object is deleted and you get a dangling reference.

I don't think there's an obvious alternate implementation that will allow you to get away with the above. When you start chaining together range adaptors, especially transforms, you have to consider whether the argument to the transformation function needs to persist for the result to be remain valid.

HTH,

- Jeff