PDA

View Full Version : QExplicitlySharedDataPointer and circular references lead to dangling pointers



Kampfgnom
28th September 2012, 11:13
Hi,

I want my classes to use QExplicitlySharedDataPointer for their shared data. Also I want several classes to reference each other.

We have ClassX and ClassY. ClassX maintains a QList<ClassY>. ClassY references exactly one ClassX. Both classes implement copy constructor and operator=(), like this:


ClassY::ClassY(const ClassY &other) :
QObject(other.parent()),
d( other.d )
{
}

ClassY &ClassY::operator =(const ClassY &other)
{
d = other.d;
return *this;
}

When we now use the following code to add/set the values, it leads to circular dependencies between the two classes:


void ClassY::setClassX(const ClassX &classX)
{
d->m_classX = classX;
}

void ClassX::addClassY(const ClassY &classY)
{
d->m_classYList.append(classY);
}


When we execute the following test, the shared data objects are never being destroyed and leak:

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

ClassX x1;
ClassY y1;

x1.addClassY(y1);
y1.setClassX(x1);

return a.exec();
}


I create the output with the help of incremental IDs for each instance of ClassX, ClassY, ClassXPrivate and ClassYPrivate:


ClassXPrivate 0
ClassX 0
ClassXPrivate 1
ClassX 1
ClassYPrivate 0
ClassY 0
~ClassXPrivate 1
~ClassY 0
~ClassX 0

As you can see, ClassYPrivate 1 and ClassXPrivate 0 are never being destructed.


You may download the small example Qt Creator project from my dropbox: http://dl.dropbox.com/u/140012/sharedatatest.zip


I came across this behavious in the libtvdb (http://sourceforge.net/projects/libtvdb/) library, in which each Series has several Seasons, which has several Episodes. Each Season knows its Series and each Episode knows its Season and Series. This leads to HUGE memory leaks, if you scrape several hundred TV shows.

Am I right, with what I am saying? How would you solve this problem?


Greetings Niklas

wysota
28th September 2012, 11:27
IMHO one reference should be a weak reference, then there won't be any problems.

Kampfgnom
28th September 2012, 11:35
What do you mean by "weak" reference? Both "references" are simple members on the stack:


ClassXPrivate {
...
QList<ClassY> m_classYList;
...
}
ClassYPrivate {
...
ClassX m_classX;
...
}


Since all objects are quite temporary, I don't want them on my heap. Thats why I don't want to reference them with the help of pointers. I just want to use them, just like we all do with QString etc.

wysota
28th September 2012, 12:54
A weak reference is one that only checks existance of the object but does not enforce that existance (in other words does not "own" the object). See the difference between QSharedPointer and QWeakPointer.