New shared pointer - revision 2

Thiago Macieira thiago at kde.org
Sat Sep 10 03:53:36 BST 2005


Frerich Raabe wrote:
>> >                KSharedPtr( T *obj = 0 )
>> >                {
>> >                        KSharedData *x = new KSharedData;
>> >                        x = qAtomicSetPtr( &d, x );
>> >                        d->ref = 1;
>> >                        obj = qAtomicSetPtr( &d->obj, obj );
>> >                }
>>
>> I think you're overkilling here with qAtomicSetPtr. There's no
>> thread-safety issue with the KSharedData variables d and x because
>> you've just allocated it.
>
>Ah okay, so 'd->obj = new KSharedData;' is okay?

According to Maksim on IRC, qAtomicSetPtr could be a memory fence, so I'd 
like to hear someone else's opinion on this. I don't understand why a 
"set pointer" function makes use of locking exchange instructions, so 
there may be a stronger reason.

What I suggested was d = new KSharedData; which looks ok to me.

>This is wrong. *this = other calls operator=( const KSharedPtr<T> & ),
> not operator=( T* ). Hence the newly allocated KSharedData won't be
> deallocated immediately (since the former assignment operator calls
> ref() on it's argument before deref()erencing).

The code path is this:
                        KSharedData *x = new KSharedData;
                        x = qAtomicSetPtr( &d, x );
                        rhs.d->ref.ref();
                        deref();
                        KSharedData *x = rhs.d;
                        x = qAtomicSetPtr( &d, x );

When deref() is called, the refcount on this (lhs) will be 1 and will, 
therefore, cause d to be deleted. If it weren't deleted, it would cause a 
memory leak because the last line sets d to rhs.d.

>
>> >                KSharedPtr<T> &operator=( T *rhs )
>> >                {
>> >                        deref();
>> >                        if ( !d ) {
>> >                                KSharedData *x = new KSharedData;
>> >                                x = qAtomicSetPtr( &d, x );
>> >                        }
>> >                        rhs = qAtomicSetPtr( &d->obj, rhs );
>> >                        d->ref = 1;
>> >                        return *this;
>> >                }

Suppose d->ref == 2.
When you call deref(), it'll call d->ref.deref() which will make d->ref == 
1 and leave d != 0. At this point, you've detached from d, so you 
shouldn't write anymore to its contents.

Since d != 0, the if-statement is false. You then run 
qAtomicSetPtr( &d->obj, rhs ) which sets d->obj on the d you've just 
detached from.

> What would make sense is to use
> 'T *get() const;' tho

You can't do that without breaking constness. It would have to be const T* 
get() const;

>P.S.: You did overlook a much more grave problem (which I already fixed
>locally). Think about what happens when one does
>'KSharedPtr<int> p; KSharedPtr<int> q = p.copy();'

Oh, right.
-- 
  Thiago Macieira  -  thiago (AT) macieira.info - thiago (AT) kde.org
    PGP/GPG: 0x6EF45358; fingerprint:
    E067 918B B660 DBD1 105C  966C 33F5 F005 6EF4 5358

4. And æfter se scieppend ingelogode, he wrát "cenn", ac eala! se 
rihtendgesamnung andswarode "cenn: ne wát hú cennan 'eall'. Ástynt."
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <http://mail.kde.org/pipermail/kde-core-devel/attachments/20050909/9545a5c8/attachment.sig>


More information about the kde-core-devel mailing list