[Telepathy] tq-qt4 refcount proposal

Andre Moreira Magalhaes andre.magalhaes at collabora.co.uk
Tue Apr 7 07:11:15 PDT 2009


Jonathon Jongsma wrote:
> Andre Moreira Magalhaes wrote:
>> First version of the proposal with all suggestions is up on my shared 
>> branch:
>> http://git.collabora.co.uk/?p=user/andrunko/telepathy-qt4.git;a=shortlog;h=refs/heads/shared 
>>
>>
>> BR
>> Andre
>
> OK, I took a look at the current implementation, and here are my 
> notes.  It's obviously possible that i've misunderstood or 
> misinterpreted something, so feel free to challenge me on any of these.
>
> [explicit inline SharedPtr(T *d) : d(d) { if (d) { d->ref(); } }]
> boost::shared_ptr uses a templated constructor for this case (e.g.  
> template
> <class Y> SharedPtr(Y *d) ...) which allows it to somehow remember the 
> actual
> pointer type passed so that if it was a different type that is 
> convertible to
> T*, it will call delete with its original type and thus will not leak 
> even if Y
> does not have a virtual destructor). Granted, they probably use some 
> black magic
> to accomplish this, but it might be worth considering.  For example, 
> consider
> this contrived example:
>   class A {};
>   class B : public A {
>   public:
>       B() : x(new int[1000]) {}
>       ~B() { delete [] x; }
>   private:
>       int * x;
>   }
>   // This will leak 1000*sizeof(int) when it goes out of scope
>   SharedPtr<A> shared(new B());
>   // whereas this does not leak:
>   boost::shared_ptr<A> boost_shared(new B());
>
Done

> [SharedData]
> Speaking of virtual destructors, SharedData should probably have one 
> if it's meant to
> be the base class of all ref-counted classes. Also, the name is rather
>
Done

> [template<class X>
> inline SharedPtr(const SharedPtr<X> &o)]
> I don't think this constructor is a good idea.  I assume this is 
> designed so that
> you can easily convert from a derived class pointer to a base class 
> pointer as you
> would with raw pointers, but I think it's much better to make the 
> programmer state
> explicitly what they want to do.  And in any case, dynamic_cast is 
> probably the more
> appropriate cast in this situation.  See also
> boost::static_pointer_cast/dynamic_pointer_cast/etc or
> Glib::RefPtr::cast_static/cast_dynamic/etc
>
Done

> [inline SharedPtr(const WeakPtr<T> &o)]
> It's probably best to make this explicit as well so that converting 
> from a weak
> pointer to a shared pointer is only done when it's intentional. You 
> also might
> consider something like the boost::weak_ptr::lock() API that allows 
> you to
> easily create a SharedPtr from a WeakPtr
>
Done

> [Copy constructor and operator=()]
> You might consider using the swap() idiom like Glib::RefPtr uses, it's 
> quite
> elegant and allows greater code reuse:
> http://svn.gnome.org/viewvc/glibmm/trunk/glib/glibmm/refptr.h?view=markup#l228 
>
>
Done

> [~SharedPtr()]
> Perhaps ~SharedPtr() should just call reset()?  You'd be doing an 
> extra 'd = 0'
> operation during destruction, but you'd eliminate some code duplication.
>
Done, but the other way, reset calls the destructor using swap

> [data()]
> You may want to think about whether data() is really necessary as a 
> public API.
> It can certainly be useful at times to access the underlying raw 
> pointer, but it
> can also encourage improper use by application developers, since they 
> can easily
> grab the pointer out and store it somewhere, which circumvents the
> reference-counting
>
This is needed, as many Qt methods as QObject::connect needs the object 
directly, so better doing this than using operator->

> [General]
> Be very careful about passing smart pointers as const references since 
> that
> circumvents the smart pointer's reference-counting mechanism.  It 
> looks like
> everywhere you use const references in the implementation of the smart 
> pointer
> are ok, but just keep it in mind (especially when you actually use 
> these classes
> other Telepathy API)
>
> You should make your API reference crystal clear that this class is 
> only for use
> with classes derived from SharedData.  No matter how obvious you think 
> it is,
> people will still assume that it's a generic smart pointer that they 
> can use
> with their arbitrary classes (this is from my experience with glibmm)
>
Yep, when docs are added to these classes I will add a note about this.

> I don't know if the goal is for this class to be threadsafe or not, 
> but strictly
> speaking, it's not. The reference count involves indirection, so 
> although the
> the integer operations are atomic, the following code is not atomic as 
> a whole:
> 'if (d) {d->ref();}'.  So while the reference count itself can not be
> corrupted, there are corner cases that could cause problems: (e.g. 
> thread A
> could test that d is not null, then another thread could decrement the 
> ref count
> to zero and delete d, and then the thread A would attempt to call 
> d->ref()).
>
That' s not the goal, as tp-qt4 is not thread-safe at all :)



Again, thanks for the review

Reviewed branch at 
http://git.collabora.co.uk/?p=user/andrunko/telepathy-qt4.git;a=shortlog;h=refs/heads/shared

BR
Andrunko



More information about the telepathy mailing list