[Telepathy] tq-qt4 refcount proposal
Andre Moreira Magalhaes
andre.magalhaes at collabora.co.uk
Fri Mar 20 13:50:23 PDT 2009
Hi all,
I would like to make a proposal for tp-qt4 refcounted classes.
1 - Rationale:
Many objects (read all high-level DBus interfaces classes AccoutManager,
Account, Channel, Connection, ...) in tp-qt4 are reference counted.
The pattern used is that classes inherit QSharedData and are used
together with QExplicitlySharedDataPointer, that takes care of managing
the reference count.
When the reference count hits 0, the object is deleted.
When instantiating new classes that inherits QSharedData without using
QExplicitlySharedDataPointer the reference count is 0, this is referred
to as the floating state.
This may lead to memory leaks, caused by objects in the floating state
that never get deleted.
2 - Proposal for avoiding objects in floating state as hard as possible:
New objects should be put into a QExplicitlySharedDataPointer as soon as
possible after creation to avoid possibly leaking an object while it’s
in a floating state.
To achieve this we could make the objects constructor protected* and
have public create function that returns a QExplicitlySharedDataPointer.
Why not make the constructor private?
We need to support subclasses, and so we need the constructors to be at
least protected.
2.1 - Problems:
2.1.1 - Circular dependency:
In the ideal world we should use QExplicitlySharedDataPointer<Object> in
the library, even for objects that needs to know about each other, for
example StreamedMediaChannel that caches the MediaStreams and
MediaStreams that have a pointer to the StreamedMediaChannel. We should
be careful with this, as we hit circular dependency, which can lead to
even more memory leaks when the objects refcount never hits 0.
This can be handled in different ways, and should be done case by case.
Bellow there is a code snippet to illustrate how to manage this on
StreamedMediaChannel/MediaStream case:
class MediaStream : public QSharedData, ... {
public:
MediaStream(const QExplicitlySharedDataPointer<StreamedMediaChannel>
&channel, ...)
: QSharedData(),
mChannel(channel) // channel->ref++
{ }
...
QExplicitlySharedDataPointer<StreamedMediaChannel> channel() const {
return mChannel; }
...
private:
...
QExplicitlySharedDataPointer<StreamedMediaChannel> mChannel;
};
class StreamedMediaChannel : public QSharedData, ... {
public:
static QExplicitlySharedDataPointer<StreamedMediaChannel> create(...) {
... }
...
QList<QExplicitlySharedDataPointer<StreamedMediaChannel> > streams()
const { return mStreams; }
...
protected:
StreamedMediaChannel(...); // StreamedMediaChannel should allow inheritance
...
private Q_SLOTS:
void onInvalidated(...) // closed
{
foreach (stream, streams) {
// if nothing else is holding the stream, the stream will be deleted
stream.reset();
}
// no stream is referencing the channel anymore, when the library user
forget about the channel,
// it will be deleted.
}
void onStreamRemoved(...)
{
...
// if nothing else is holding the stream, the stream will be deleted
stream.reset();
...
}
private:
...
QList<QExplicitlySharedDataPointer<MediaStream> > mStreams;
};
2.1.2 - Custom classes:
All custom classes should follow this guideline, making the constructor
protected and having a create method, to avoid objects in floating
state, as explained above.
2.1.3 - QObject parent relationship:
All refcounted objects should not have a parent QObject, as when the
QObject gets deleted the children objects are deleted as well.
3 - Naming:
As you can see typing QExplicitlySharedDataPointer all over the place is
not something really nice, and we may want to move to another class
later, a lightweight version or something else, so the ideal is to have
our own class that for now inherits QExplicitlySharedDataPointer, and if
we want to change it later we just change this class.
Note that typedef is not an option here, as you can't typedef template
(just template specializations) and can't forward declare typedef, which
we would need.
So I propose to have a template class SharedPtr that inherits
QExplicitlySharedDataPointer, and a class named SharedData that is a
typedef for QSharedData (in case we want to change to use another class
in the future, we don't need to change all classes). We may want to make
SharedData call deleteLater on ref==0 instead of delete for example.
So the usage would be:
public Account : SharedData
{
public:
...
static SharedPtr<Account> create();
...
};
I wrote a experimental branch to ilustrate what it's explained above
http://git.collabora.co.uk/?p=user/andrunko/telepathy-qt4.git;a=shortlog;h=refs/heads/shared
Opinions, suggestions?
BR
Andrunko
P.s.: Some ideas are based on http://webkit.org/coding/RefPtr.html, as
suggested by Kenneth Rohde Christiansen.
More information about the telepathy
mailing list