PDA

View Full Version : DeleteLater works... but why?



TheGrimace
5th June 2007, 18:49
I have been debugging a multi-threaded application for a while now.

Recently I had been getting Heap corruption breakpoints from VS .net and had been trying to locate the source.

I found the source in a widget that deleted another widget directly. Apparently some part of the code was still pointing to it after i deleted it. (It wasn't any of my written code, but it may have been Qt or MS generated)

Anyway, on a hunch i tried deleteLater for the sub-widget, and it worked like a charm. (No more heap corruption errors at any rate)

I am wondering if there is any reason deleting a widget directly is bad in a multi-threaded application?

(Can't post any of my code as it does not belong to me. It belongs to my company)

marcel
5th June 2007, 18:56
A QObject automatically deletes all its children when itself is deleted.

So, I assume that after you deleted that widget, and it deleted it's children, there remained some references throughout the app to the invalid children.
Therefore it does not matter that the app is multithreaded or not.

Why not "deleteLater" the parent widget?

Regards

wysota
5th June 2007, 20:21
Did you try to delete the object from within a slot that took it as an argument?

TheGrimace
5th June 2007, 21:18
I should explain more specifically:

I am placing a new Widget pointer (call it widgetA) in a struct-like QObject class. (all data members public)

That widgetA performs a function, sends a signal to the struct-like Qobject's creator, who then deletes the widgetA and the struct-like widget.

The signal being received is a unique variable to that object that allows me to search a list for the object while under the protection of a mutex locker.

In this case the VS .NET would complain on the very next new memory allocation about a heap corruption.

If I use deleteLater on the widgetA and then also on the struct-like Qobject, it no longer has this issue.

wysota
5th June 2007, 21:41
Could you please answer my question?

TheGrimace
5th June 2007, 21:44
The signal being received is a unique variable to that object that allows me to search a list for the object while under the protection of a mutex locker.


As I said, I am receiving a unique variable (in this case an integer) so the answer to your question is no.

wysota
5th June 2007, 22:31
But you receive from where? Maybe in the chain of calls the object that gets deleted in one of "subslots" is passed as a signal parameter at some point?

TheGrimace
5th June 2007, 22:35
I never pass any objects by reference in this particular case.

I receive the signal emitted from widgetA into the object that deletes it. The signal contains a unique integer passed by value. I believe Qt::AutoConnection turns the connection into a direct connection.

wysota
5th June 2007, 23:05
Let me explain... Imagine we have a following situation:

class A : public QObject{
//...
signals:
void sigA(QObject *);
};
class B : public QObject{
//...
signals:
void sigB(int);
public slots:
void slotB(QObject *o){ emit sigB(m_list.indexOf(o)); }
};

class C : public QObject {
//...
public slots:
void slotC(QObject *o){...}
};
Now imagine we connect sigA to slotB and slotC and sigB to some slot that deletes the item pointed by the integer emited from sigB. If sigA is emitted, slotB is called and emits sigB which in turn calls a slot that deletes the item. Seems fine... But then slotC is called and tries to operate on the same object. But it has already been deleted! Hence the crash. Now if you use deleteLater(), the object is deleted only after all slot have been called. That's probably the problem you're facing, but I can't be sure without seeing your code.

TheGrimace
6th June 2007, 15:16
Would I get the same same result if the instance of A&C were inside of B?

IE

A&C -> signals -> B

B -> signals -> D (the object that created B) to delete it.

but A and C are new instances of those classes created in B.

kind of like:



class A : public QObject{
//...
signals:
void sigA(QObject *);};
class B : public QObject{
//...
B() { a= new A(); b=new B(); connect(AtoB); connect(CtoB);}
signals:
void sigB(int);
public slots:
void slotB(QObject *o){ emit sigB(m_list.indexOf(o)); }
};
class C : public QObject {
//...
public slots:
void slotC(QObject *o){...}
};
class D : public QObject {
//...
public:
D() { b = new B(); connect(B to D);}
public slots:
DSlot() { delete b or deletelater b}
};

and B initiates a call to the D Slot which deletes it and its children.

wysota
6th June 2007, 15:47
The relationship doesn't matter. The only thing that matters is that more than one slot operates on the same object that gets deleted in one of the slots. If that is the case, you have to use deleteLater() or somehow check if the pointer is stil valid (checking for null won't do).

TheGrimace
6th June 2007, 16:14
That is most likely what was going wrong then.

Thank You for your help.