Page 1 of 2 12 LastLast
Results 1 to 20 of 32

Thread: Q_FOREACH deleting objects

  1. #1
    Join Date
    Apr 2007
    Location
    Bangalore,India
    Posts
    25
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    2

    Unhappy Q_FOREACH deleting objects

    Hello ,
    This is an interesting problem. I iterate over a list of children() (defined in QObject). Initially there are 7 children. Then iterating over the contianer, I check for a particular object. If found I delete it.
    Now the problem:::
    1) Start Iterator with count as 7
    2) Found object at position 4th in the container.
    3) The object matches and I delete it.
    4) Now the count of the container is 6.
    5) Now according to me the container should resize automatically and should shift the objects. But it doesnt happen and my application crashes.

    Any idea Why????

    Qt Code:
    1. Q_FOREACH( QObject *obj, children() )
    2. {
    3. if( obj->isA( "myObject" ) )
    4. (qobject_cast<myObject *>(obj))->deleteSelected();
    5. }
    To copy to clipboard, switch view to plain text mode 

    Thanks,
    Veda.

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: Q_FOREACH deleting objects

    I suggest you use deleteLater() and forget about the problem

    And seriously, I assume children() returns a QList<QObject*>. If you delete an object pointed by a pointer, you don't delete the pointer itself, therefore it is still a valid "object" and occupies space in the list. The list is not "smart" in any way and doesn't know or care what you keep in your pointers.

  3. #3
    Join Date
    Mar 2006
    Location
    Mountain View, California
    Posts
    489
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows
    Thanks
    3
    Thanked 74 Times in 54 Posts

    Default Re: Q_FOREACH deleting objects

    Q_FOREACH and foreach use implicit sharing (copy-on-write). If you modify the container, a copy will be made, and the iteration will continue in the unmodified copy.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: Q_FOREACH deleting objects

    Quote Originally Posted by Brandybuck View Post
    Q_FOREACH and foreach use implicit sharing (copy-on-write).
    Actually this is not true. Implicit sharing indeed is used by foreach() here but it is only because Qt containers are implicitely shared. If you pass a non-shared container to foreach, it'll get deep copied.

  5. #5
    Join Date
    Mar 2006
    Location
    Mountain View, California
    Posts
    489
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows
    Thanks
    3
    Thanked 74 Times in 54 Posts

    Default Re: Q_FOREACH deleting objects

    Quote Originally Posted by wysota View Post
    Actually this is not true. Implicit sharing indeed is used by foreach() here but it is only because Qt containers are implicitely shared.
    That's what I meant.

  6. #6
    Join Date
    Sep 2006
    Posts
    339
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    15
    Thanked 21 Times in 16 Posts

    Default Re: Q_FOREACH deleting objects

    I suggest you use deleteLater() and forget about the problem
    According to QtAssistence--> Defination of deleteLater()
    "Schedules this object for deletion.
    The object will be deleted when control returns to the event loop."

    Is it possible to return the control to the event loop immediately after the object is deleted. Or in other words how do I return the control such that my object gets deleted immediately.

    Also, since children() gets updated immediately after any object is deleted, I think pointer to an object should also get deleted. I have written a sample program where the deletion happens without any problem.
    Qt Code:
    1. class myObject;
    2. class mainObject : public QObject{
    3. public:
    4. mainObject( QObject * parent = 0 ) : QObject( parent ){}
    5. ~mainObject(){}
    6. void deleteTheObject();
    7. };
    8. class myObject : public mainObject{
    9. public:
    10. myObject( QObject * parent = 0 ) : mainObject( parent ){}
    11. ~myObject(){}
    12. void deleteSelected(){
    13. delete this;
    14. }
    15. private:
    16.  
    17. };
    18. void mainObject::deleteTheObject(){
    19. Q_FOREACH( QObject* obj, children() ){
    20. qDebug() << children().count();
    21. if( obj->objectName() == "c" ){
    22. ((myObject*)obj)->deleteSelected();
    23. }
    24. }
    25. }
    To copy to clipboard, switch view to plain text mode 

    Uses
    Qt Code:
    1. int main(int argc, char *argv[]){
    2. mainObject* ob = new mainObject;
    3. myObject* a = new myObject(ob);
    4. a->setObjectName( "a" );
    5. myObject* b = new myObject(ob);
    6. b->setObjectName( "b" );
    7. myObject* c = new myObject(ob);
    8. c->setObjectName( "c" );
    9. myObject* d = new myObject(ob);
    10. d->setObjectName( "d" );
    11. myObject* e = new myObject(ob);
    12. e->setObjectName( "e" );
    13. ob->deleteTheObject();
    14. return 0;
    15. }
    To copy to clipboard, switch view to plain text mode 
    In the above program, after the object is deleted, children() gets updated, the count is decreased.
    I tried modifying the above program with below given statement, But was unsuccessful.
    If you delete an object pointed by a pointer, you don't delete the pointer itself, therefore it is still a valid "object" and occupies space in the list.
    How do i delete the pointer to an object in QList<QObject*>????

    Wysota, can you please clear my funda.
    One more small doubt.
    In qt3 children() is a typedef for QList<QObject> and in Qt4 it is QList<QObject*>. Can you please clear me about this. what happens when object is deleted in both cases. I read Assistance, but there is still confusion.

    Thanks
    Last edited by vermarajeev; 15th May 2007 at 06:07.

  7. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: Q_FOREACH deleting objects

    Quote Originally Posted by vermarajeev View Post
    According to QtAssistence--> Defination of deleteLater()
    "Schedules this object for deletion.
    The object will be deleted when control returns to the event loop."

    Is it possible to return the control to the event loop immediately after the object is deleted. Or in other words how do I return the control such that my object gets deleted immediately.
    Don't worry about that. Once you return from the slot all items scheduled for deletion will be deleted. I'd call it an "immediate" action.

    Also, since children() gets updated immediately after any object is deleted, I think pointer to an object should also get deleted.
    No, of course not. You have a list of "objects" where the "object" is a pointer. And that "object" will remain there as long as you don't remove it from the list, no matter what it holds.

    I have written a sample program where the deletion happens without any problem.


    Qt Code:
    1. class myObject;
    2. class mainObject : public QObject{
    3. public:
    4. mainObject( QObject * parent = 0 ) : QObject( parent ){}
    5. ~mainObject(){}
    6. void deleteTheObject();
    7. };
    8. class myObject : public mainObject{
    9. public:
    10. myObject( QObject * parent = 0 ) : mainObject( parent ){}
    11. ~myObject(){}
    12. void deleteSelected(){
    13. delete this;
    14. }
    15. private:
    16.  
    17. };
    18. void mainObject::deleteTheObject(){
    19. Q_FOREACH( QObject* obj, children() ){
    20. qDebug() << children().count();
    21. if( obj->objectName() == "c" ){
    22. ((myObject*)obj)->deleteSelected();
    23. }
    24. }
    25. }
    To copy to clipboard, switch view to plain text mode 

    Uses
    Qt Code:
    1. int main(int argc, char *argv[]){
    2. mainObject* ob = new mainObject;
    3. myObject* a = new myObject(ob);
    4. a->setObjectName( "a" );
    5. myObject* b = new myObject(ob);
    6. b->setObjectName( "b" );
    7. myObject* c = new myObject(ob);
    8. c->setObjectName( "c" );
    9. myObject* d = new myObject(ob);
    10. d->setObjectName( "d" );
    11. myObject* e = new myObject(ob);
    12. e->setObjectName( "e" );
    13. ob->deleteTheObject();
    14. return 0;
    15. }
    To copy to clipboard, switch view to plain text mode 
    In the above program, after the object is deleted, children() gets updated, the count is decreased.
    Because children() returns a new list and you're iterating over the old one as Brandybuck already said.


    How do i delete the pointer to an object in QList<QObject*>????
    Remove it from the list. Of course you can't do it in foreach() as you don't have access to the list, so basically what you want is not possible to do using foreach(). You should use iterators instead.

    One more small doubt.
    In qt3 children() is a typedef for QList<QObject> and in Qt4 it is QList<QObject*>.
    No. In Qt3 it's a typedef for QPtrList<QObject> which is exactly the same as QList<QObject*> in Qt4.

    Can you please clear me about this. what happens when object is deleted in both cases. I read Assistance, but there is still confusion.
    Nothing. The object pointed gets deleted and that's it. You're left with a dangling pointer in the list.

  8. The following user says thank you to wysota for this useful post:

    vermarajeev (15th May 2007)

  9. #8
    Join Date
    Apr 2007
    Location
    Bangalore,India
    Posts
    25
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    2

    Default Re: Q_FOREACH deleting objects

    Hello guys,

    The below given is a code in Qt3
    Qt Code:
    1. QObjectList *list;
    2. QObjectListIt *it;
    3. QObject *obj;
    4.  
    5. if( (list = (QObjectList *)children()) != 0 )
    6. {
    7.  
    8. it = new QObjectListIt( *list );
    9. // for each found object...
    10.  
    11. while ( (obj = it->current()) != 0 )
    12. {
    13. ++(*it);
    14. if( obj->isA( "myObject" ) )
    15. ((myObject *)obj)->deleteSelected();
    16. }
    17. delete it;
    18. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. deleteSelected()
    2. {
    3. delete this;
    4. }
    To copy to clipboard, switch view to plain text mode 

    I tried to port it using Q_FOREACH... as discussed above using Q_FOREACH is not a good idea...

    so how can i achieve the same functionality in Qt4



    Veda

  10. #9
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: Q_FOREACH deleting objects

    As I said, use iterators of the list to manipulate the list directly. That's exactly what the above Qt3 code does.

  11. #10
    Join Date
    Apr 2007
    Location
    Bangalore,India
    Posts
    25
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    2

    Default Re: Q_FOREACH deleting objects

    Quote Originally Posted by wysota View Post
    As I said, use iterators of the list to manipulate the list directly. That's exactly what the above Qt3 code does.
    I just did it but again there is a dangling pointer and the application crashes. Any idea???
    Qt Code:
    1. QObjectList *list;
    2. QListIterator<QObject*> *it;
    3. QObject *obj;
    4. list = new QObjectList( children() );
    5. if( list->count() != 0 )
    6. {
    7. it = new QListIterator<QObject*>( *list );
    8. while ( it->hasNext() )
    9. {
    10. obj = it->next();
    11. if( obj->isA( "myObject" ) )
    12. ((myObject *)obj)->deleteSelected();
    13. }
    14. delete it;
    15. }
    16. delete list;
    To copy to clipboard, switch view to plain text mode 

  12. #11
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: Q_FOREACH deleting objects

    Qt Code:
    1. QObjectList list = children();
    2. for(QList<QObject*>::iterator it = list.begin(); it!=list.end();++it){
    3. if(*it && (*it)->isA("myObject")){
    4. delete (*it);
    5. (*it) = 0;
    6. }
    7. }
    To copy to clipboard, switch view to plain text mode 

    Of course it'd be quicker to do:
    Qt Code:
    1. qDeleteAll(qFindChildren<myObject*>(this));
    To copy to clipboard, switch view to plain text mode 
    and with a bit of luck it wouldn't crash

  13. #12
    Join Date
    Apr 2007
    Location
    Bangalore,India
    Posts
    25
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    2

    Default Re: Q_FOREACH deleting objects

    Sorry, I tried the above code too but the result is same.
    Qt Code:
    1. QObjectList list = children();
    2.  
    3. for(QList<QObject*>::iterator it = list.begin(); it!=list.end(); ++it)
    4. {
    5. qDebug() << children().count();
    6. qDebug() << list.count(); //the list( with 7 children ) is
    7. //always same even after deleting the childrens but
    8. //children() shows me correct count ie 6 (after deleting one object)
    9. // but list is still 7. Meaning there is still dangling pointer.
    10. if(*it && (*it)->isA( "myObject" ))
    11. {
    12. ((myObject *)(*it))->deleteSelected();
    13. if( ((myObject*)(*it))->isSelected() )
    14. (*it) = 0;
    15. }
    16. }
    To copy to clipboard, switch view to plain text mode 
    I think the pointer is still existing and the object is deleted. But it works fine with Qt3 code. Please help...

  14. #13
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: Q_FOREACH deleting objects

    Why can't you understand that children() returns a new (updated) list each time you call it?
    Number of children is updated every time you delete a child, so children() returns a list with an updated count, but the old list is not updated so it still has a count of 7.

    There is no dangling pointer because the pointer in the list is set to 0 in line #14 and it is checked for being 0 in line #10. If it doesn't work, it means the error is elsewhere.

    Please try using qFindChildren as suggested. It has a good chance to work without you having to bother about the list at all.

  15. #14
    Join Date
    Apr 2007
    Location
    Bangalore,India
    Posts
    25
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    2

    Default Re: Q_FOREACH deleting objects

    Sorry, if I mistook you..

    Ok let me explain what is happening.

    Qt Code:
    1. QObject -- Has 7 children()
    2.  
    3. ____________________|______________________________________
    4. | | | | | |
    5. object1 object2 object3 object4 object5 object6
    6. | \
    7. object7 \
    8. --> This object matches and I delete this
    9.  
    10.  
    11. object7 --> Since this is a child of object5. object7 also gets deleted after object5
    To copy to clipboard, switch view to plain text mode 

    Explanation:::
    Now QObject has seven children(), I iterate over the list. 'object5' matches my criteria so I delete 'object5'. Since 'object5' has one child 'object7' (which is also a child of 'QObject'), 'object7' too gets deleted along with 'object5'.
    So what has happened now, both 'object5'(parent) and 'object7'( child of object5 )are deleted. When the iterator from 'QObject' points to last child (object7), tries to access an object which is already deleted (object7). Hence the program crashes.

    I think now I'm clear. I also tried calling deleteLater on the object to be deleted but then object doesnt really get deleted (as it schedules to delete) and hence doesnt satisfy my application criteria, so crashes again. Hence I cannot use deleteLater either.

    I dont understand, as the same functionality works fine with Qt3.


    Veda
    Last edited by veda; 16th May 2007 at 09:29.

  16. #15
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: Q_FOREACH deleting objects

    use deleteLater() and call QCoreApplication::processEvents() afterwards.

  17. #16
    Join Date
    Sep 2006
    Posts
    339
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    15
    Thanked 21 Times in 16 Posts

    Default Re: Q_FOREACH deleting objects

    Explanation:::
    Now QObject has seven children(), I iterate over the list. 'object5' matches my criteria so I delete 'object5'. Since 'object5' has one child 'object7' (which is also a child of 'QObject'), 'object7' too gets deleted along with 'object5'.
    So what has happened now, both 'object5'(parent) and 'object7'( child of object5 )are deleted. When the iterator from 'QObject' points to last child (object7), tries to access an object which is already deleted (object7). Hence the program crashes.
    What about using a QPointer. Assign your objects to QPointer, once the object is deleted it makes the pointer NULL. Might help...

  18. #17
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: Q_FOREACH deleting objects

    Yes, but you have to construct your own list then. And if you do, there is no point in using QPointer anymore as you can make sure children get deleted before parents.

  19. #18
    Join Date
    Sep 2006
    Posts
    339
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    15
    Thanked 21 Times in 16 Posts

    Default Re: Q_FOREACH deleting objects

    Quote Originally Posted by wysota View Post
    Yes, but you have to construct your own list then. And if you do, there is no point in using QPointer anymore as you can make sure children get deleted before parents.
    But OP says "Hence I cannot use deleteLater either."

    I too have a doubt about using deleteLater, what if I have defined my own deleteFunction where I perform some functionality about destruction. In that case if you use deleteLater my deleteFunction wont be called and there will definately be many crashes.

    I need this information coz I too have my application to port to Qt4. So I would like to know what changes to be made so that I'm safe.

    Will it really effect my fuctionality changing QPtrList<QObject>(Qt3) to QList<QObject*>(Qt4)

  20. #19
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: Q_FOREACH deleting objects

    Quote Originally Posted by vermarajeev View Post
    But OP says "Hence I cannot use deleteLater either."
    Sure he can. It's enough to use processEvents() just after iterating the list.

    I too have a doubt about using deleteLater, what if I have defined my own deleteFunction where I perform some functionality about destruction. In that case if you use deleteLater my deleteFunction wont be called and there will definately be many crashes.
    It's your fault then. You should have implemented that in the destructor. That's what it's meant for. Of course you don't have to rely on the destructor and implement your own deleteLater() which will post a custom event to the event queue and trigger your own destruct process in its handler. But this is just a theory as all QObject subclasses have to be prepared to be destroyed automatically, so it should all be handled in the destructor.

  21. #20
    Join Date
    Apr 2007
    Location
    Bangalore,India
    Posts
    25
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    2

    Default Re: Q_FOREACH deleting objects

    Hello guys...

    Still unable to solve the problem...

    I have provided the code below with the same senario what i was trying to explain in my other posts.

    Without changing the class hierarchy i need to solve the problem of deleting the object.

    I tried using deleteLater() .. still the problem remains... So, I cannot use deleteLater too..





    Qt Code:
    1. #include <QtGui/QApplication>
    2. #include <QDebug>
    3.  
    4. class parentObject : public QObject
    5. {
    6. public:
    7. parentObject( QObject* parent = 0 ) : QObject(parent){}
    8. ~parentObject(){}
    9. protected:
    10. void deleteSelected();
    11. };
    12.  
    13. class child1 : public parentObject
    14. {
    15. public:
    16. child1( QObject* parent = 0 ) : parentObject(parent){}
    17. ~child1(){}
    18. void deleteSelect()
    19. {
    20. delete this;
    21. }
    22. };
    23.  
    24. class child2 : public parentObject
    25. {
    26. public:
    27. child2( QObject* parent = 0 ) : parentObject(parent)
    28. {}
    29. ~child2(){
    30.  
    31. }
    32. void deleteSelect()
    33. {
    34. delete this;
    35. }
    36. };
    37.  
    38. class child3 : public parentObject
    39. {
    40. public:
    41. child3( QObject* parent = 0 ) : parentObject(parent){}
    42. ~child3(){}
    43. void removeChild2( child2* c )
    44. {
    45. c->deleteSelect();
    46. delete this;
    47. }
    48.  
    49. };
    50.  
    51. int main(int argc, char *argv[])
    52. {
    53. parentObject* obj = new parentObject;
    54. child1* c11 = new child1(obj);
    55. c11->setObjectName ( "child1" );
    56. child1* c12 = new child1(obj);
    57. c12->setObjectName ( "child1" );
    58. child1* c13 = new child1(obj);
    59. c13->setObjectName ( "child1" );
    60.  
    61. child2* c21 = new child2(obj);
    62. c21->setObjectName ( "child2" );
    63. child2* c22 = new child2(obj);
    64. c22->setObjectName ( "child22" );
    65. child2* c23 = new child2(obj);
    66. c23->setObjectName ( "child2" );
    67.  
    68. child3* c31 = new child3(obj);
    69. c31->setObjectName ( "child3" );
    70.  
    71. QList<QObject*> list = obj->findChildren<QObject*>();
    72. for( QList<QObject*>::iterator it = list.begin(); it != list.end(); ++it )
    73. {
    74. qDebug() << (*it)->objectName();
    75. if( (*it)->objectName() == QString("child22") )
    76. {
    77. c31->removeChild2( c22 );
    78. }
    79. }
    80.  
    81.  
    82. return 0;
    83. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by veda; 21st May 2007 at 16:08.
    Veda

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.