Boost logo

Boost Users :

Subject: Re: [Boost-users] Use boost::shared_ptr with boost::adaptors
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2012-04-30 18:13:28


On Mon, Apr 30, 2012 at 3:05 AM, Robert Jones <robertgbjones_at_[hidden]>wrote:

> On Sat, Apr 28, 2012 at 9:45 PM, Jeffrey Lee Hellrung, Jr. <
> jeffrey.hellrung_at_[hidden]> wrote:
>
>> 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.
>>
>>
> When you put it that way I can see your point, but just from the code the
> OP presented the intermediate shared_ptr's should persist until
> the end of the expression.
>

I'm not sure what you mean here; do you mean there's a bug on the boost
side of the things in the original code listing?

> Just musing here, but how about if the dereference function you imagined
> returned a proxy reference, to keep the shared_ptr alive? Not
> sure how I'd implement that in practise, since it would be required to
> know foo_ptr was a shared_ptr, but maybe it could done at the level
> of the indirected adaptor rather than the indirection iterator.
>

Something like that might be possible but the reality is that this problem
persists regardless of whether you use shared_ptr or not. AFAIK, there's no
way to generically and automatically detect whether

return_type foo()
{ return f(g(bar)); }

is "safe" (e.g., leaves no dangling references) for arbitrary combinations
of f and g (even assuming bar's scope is beyond foo's), no matter what kind
of acrobats you use to detect rvalues and lvalues or whatever, and if you
go with a conservative implementation in any scenario, it's *probably*
going to give sub-optimal performance in real use cases. That's just my
guess and intuition...

- Jeff



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net