Boost logo

Boost Users :

From: Jean-François Brouillet (verec_at_[hidden])
Date: 2005-05-15 14:11:51


Gottlob Frege wrote:

>>> void intrusive_ptr_add_ref(ObjectStruct * p) { p->refer
>>> () ; }
>>> void intrusive_ptr_release(ObjectStruct * p) { p->unrefer
>>> () ; }
>>>
>
> Are you going to make it thread-safe (or is that something you just
> left out of the example?)?

Well, I left it out of the example since my main focus was on
getting it to work _at all_. So, yes, I've seen the multi-threading
tricks that shared_ptr & friends do use, and I want to take advantage
of that.

... But I'm not there yet, unfortunately. Something that escaped
my attention when I first ran (and then posted) the snippet is that
I've still got a problem to solve :-(

> struct MyTaskStruct : public LongTaskStruct
> , TaskDoneStruct {
>
> MyTaskStruct() {
> setCallback(TaskDone(this)) ;
> }

The problem here, is that setCallback is called from
the constructor, at a time when

> MyTask myTask(new MyTaskStruct) ;

hasn't finished executing yet. So the "myTask" intrusive
pointer doesn'y exist yet. In fact the issue is even
more subtle but here it goes:

The "TaskDone(this)" is perfectly fine, except that setCallback
stores it into a member of MyTaskStruct. In turn, this means
that when "myTask" is finally created on the stack, the refCount
is alreadly 1. Which it increments to 2.

When "myTask" goes out of scope, it rightly decrements the
refCount, but because the object itself now embeds a pointer
to itself, the refCount never reaches 0.

The reason I didn't catch this at first is because, the test
case also specified aternate callback in which case the
embedded pointer inside myTask is *not* referring to itself,
so when nyTask gooes out of scope, the refCount drops to 0
and then the embedded pointer unrefer is called, which in
turn destroys the referred to callback.

Obviously, this is unacceptable. I'm working on this.

The following is a perfectly legal Java idiom which I
find all over the place in the source I am porting.

Basically it says: For simple use, just use me as is.
I implement a default policy regarding so and so. However
you are free to specify your own policy when required:

     interface I {
         void i() ;
     }

     class C implements I {

         I myI ;

         void i() {
             System.out.println("I.i() called, as implemented by C") ;
         }

         C() {
             myI = this ;
         }

         void
         setI(I i) {
             myI = i ;
         }

         void f() {
             myI.i() ;
         }
     }

The equivalent C++ code would be something along the lines:

     struct IStruct {
         virtual void i() = 0 ;
     } ;

     typedef intrusive_ptr<IStruct> I ;

     struct CStruct : public IStruct {

         I myI ;

         CStruct() {
             myI = I(this) ;
         }
     } ;

     typedef instrusive_ptr<CStruct> C ;

But this code would fail because of the above problem, where
the embedded myI would refer to the same object as the outer
smart pointer.

Still digging ... :-(

--
JFB

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