Boost logo

Boost :

From: Andreas Huber (ahd6974-spamgroupstrap_at_[hidden])
Date: 2004-10-25 13:17:00


colin.rafferty_at_[hidden] wrote:
> "Andreas Huber" <ahd6974-spamgroupstrap_at_[hidden]> wrote:
>> colin.rafferty_at_[hidden] wrote:
>> For this to work, intrusive_ptr_add_ref and intrusive_ptr_release
>> functions accepting a Bar * (or a base class pointer) must exist.
>> That is, someone already decided that *all* heap-allocated Bar
>> objects will be intrusively reference-counted. Creating a
>> heap-allocated Bar object without immediately passing the pointer to
>> the intrusive_ptr constructor is dangerous. Is there a reason why
>> you do that?
>
> I agree. However, sometimes I don't have control over my base classes
> (or at least, they can surprise me). Imagine the case where a 3rd
> party library doesn't have a very good interface:
>
> class Base;
> extern void foo(Base*);
>
> I create a derived class and use it cleanly.
>
> class Derived : public Base { /* ... */ };
>
> void baz()
> {
> scoped_ptr<Derived> dptr(new Derived);
> foo(dptr.get());
> }
>
> In the next version of the library, someone has talked to the
> developers, and they've made it safer:
>
> extern void intrusive_ptr_add_ref(Base* p);
> extern void intrusive_ptr_release(Base* p);
>
> extern void foo(const intrusive_ptr<Base>&);
>
> My existing code in `baz' still compiles, but now I have the
> double-delete problem.

This is a good example why any form of automatic cleanup (in this case
reference counting) should be introduced right at the beginning. Doing
it afterwards breaks a few very crucial assumptions. In this particular
example it is just wrong to write scoped_ptr< Dervied > dptr( new
Derived ). scoped_ptr doesn't know about the RCness of Derived objects
and will inevitably do the wrong thing. You're just lucky if it works
anyway. For example, imagine what happens if the Base member function
foo() calls another function bar() to which it passes an intrusive_ptr
pointing to the Base object (i.e. the Base object passes a pointer to
itself). Calling foo() on a Base object that is not initially owned by
an intrusive_ptr will likely lead to a disaster.

>> I can't speak for Peter but I believe he made intrusive_ptr
>> constructor non-explicit because there is no room for abuse as long
>> as you follow the best practices he describes. The same isn't true
>> for heap-allocated objects pointed to by a shared_ptr.
>
> I agree that an intrusive_ptr is less likely to get bitten by the
> implicit constructor than a shared_ptr. However, I can see three
> reasons why it should still be explicit:
>
> 1. It is still potentially dangerous.

It isn't as long as you follow the best practices described in the
smart_ptr docs. The example above shows that even if the ctor was
explicit you'd need to follow these guidelines anyway. So there's no
point in making it explicit.

> 2. It is consistant with every other pointer class in boost and std.

Why should it be consistent? The reason why the other pointers have an
explicit ctor does not apply to intrusive_ptr.

> 3. There is no time when someone would actually want the implicit
> conversion

Yes there is, I'm using intrusive_ptr and some of my code relies on the
implicit conversion (this is useful when you need to pass an
intrusive_ptr pointing to this to a function).

Regards,

-- 
Andreas Huber
When replying by private email, please remove the words spam and trap
from the address shown in the header. 

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk