Results 1 to 6 of 6

Thread: Deleting from TreeWidget... Memoryleak

  1. #1
    Join Date
    Jan 2007
    Posts
    209
    Thanks
    34
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Deleting from TreeWidget... Memoryleak

    I know it deletes automatically any QObjects but for some reason the delete of QTreeWidgetItems causes problems.

    What happens with the following code is, I use SafeDeleteItem to delete a QTreeWidgetItem or a USER from the list. However, sometimes when users are deleted from the list more and more of them begin to exist (because we dont delete them live, if we do use delete pItem it will CRASH the program).

    I mean pretend I click CreateOwnerGroup button, and suddenly a group is created, and then pretend I click DeleteOwnerGroup Button... Well now the group I just made is GONE. However, since we didn't use delete... If I press Create Delete Create Delete Create Delete like 50 times, i'll have like 50 MBs of more memory in the processlist because the TreeWidgets are never deleted, they just disappear, but more and more memory adds up, and pretty soon if a user abuses this they can crash their comp because of too much memory use (its a memory leak).

    Can anyone help me properly delete?
    I do not understand why Qt doesn't have a simple function like this:
    QTreeWidget->deleteRow(QTreeWidgetItem*);

    Example is like you would delete using the following code:
    Qt Code:
    1. static void SafeDeleteItem( QTreeWidgetItem *pItem )
    2. {
    3. QTreeWidgetItem *pParent = pItem->parent();
    4. assert( pParent );
    5. int idx = pParent->indexOfChild( pItem );
    6. pParent->takeChild( idx );
    7. //delete pItem; // mem leak WTF! FIXME
    8. }
    9.  
    10. void Cclass::DeleteUser( int id, bool wasOwner)
    11. {
    12. QString qsDisplayName = m_pMainClass->GetUserInfo(id).DisplayName();
    13. QString qsChatMsg(QString("<span style=\"color: #858585;\">&lt;%1 has been deleted from list&gt;</span>").arg(qsDisplayName));
    14. echoLog(qsChatMsg);
    15.  
    16. if(wasOwner){ // if the user was the owner of the list, then move the users up
    17. // delete MapItems[id]; // delete first from the std::map!!!
    18. SafeDeleteItem(MapItems[id]);
    19. //MapItems.erase(id); // remove old item
    20. LOG("a");
    21. // delete MapItems[GetOwner()]; // remove old item for the new host
    22. SafeDeleteItem(MapItems[GetOwner()]);
    23. LOG("b");
    24. MapItems[GetOwner()] = new QTreeWidgetItem(OwnerTopLevelNode); // spawn new item for the new Owner
    25. MapItems[GetOwner()]->setText(0, m_pMainClass->GetUserInfo(GetOwner()).DisplayName());
    26. LOG("c");
    27. }
    28. else
    29. {
    30. // If they weren't owner just delete their item
    31. // delete MapItems[id];
    32. SafeDeleteItem(MapItems[id]);
    33.  
    34. MapItems.erase(id);
    35. }
    36. }
    To copy to clipboard, switch view to plain text mode 

    Basically this code

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

    Default Re: Deleting from TreeWidget... Memoryleak

    You can't delete objects which are arguments to the slot you want the delete to take place in, because it will confuse other slots that may be connected to the same signal. Instead you can use a 0 timeout timer that will fire after all the slots and there you can perform the deletion.

    Qt Code:
    1. QQueue<QTreeWidgetItem*> delqueue;
    2. void X::someSlot(QTreeWidgetItem *pItem){
    3. QTreeWidgetItem *pParent = pItem->parent();
    4. int idx = pParent->indexOfChild( pItem );
    5. pParent->takeChild( idx );
    6. delqueue.enqueue(pItem);
    7. QTimer::singleShot(0, this, SLOT(deleteWaiting()));
    8. }
    9. void X::deleteWaiting(){
    10. while(!delqueue.isEmpty())
    11. delete delqueue.dequeue();
    12. }
    To copy to clipboard, switch view to plain text mode 

  3. #3
    Join Date
    Jan 2007
    Posts
    209
    Thanks
    34
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Deleting from TreeWidget... Memoryleak

    It's not a slot or a signal though. It has nothing to do with either. It's not connected to anything.

    Let me show you a more detailed code for that, this is updated with logs so we can see better, there must be a bug in Qt or something because this makes no sense:
    Qt Code:
    1. inline static void SafeDeleteItem( QTreeWidgetItem *pItem )
    2. {
    3. QTreeWidgetItem *pParent = (QTreeWidgetItem*)pItem->parent();
    4. LOG("SafeDelete Text: %s (%x)", Q2A( pItem->text( 0 ) ), pItem );
    5. assert( pParent );
    6. int idx = pParent->indexOfChild( pItem );
    7. LOG("index=%d; ParentText: %s",idx, Q2A( pParent->text(0) ));
    8. LOG("Can We access pItem? %s %s", Q2A( pItem->text(0) ), Q2A(pItem->parent()->text(0)));
    9. pParent->takeChild( idx );
    10. LOG("Can We access Parent? %s", Q2A( pParent->text(0) ));
    11. LOG("Can We access pItem? %s %s", Q2A( pItem->text(0) ), Q2A(pItem->parent()->text(0)));
    12.  
    13. ASSERT( !pItem->parent() );
    14. ASSERT( pParent->indexOfChild ( pItem ) == -1 );
    15. ASSERT( !pItem->treeWidget() );
    16. LOG("parent=%d",pParent->treeWidget() );
    17. ASSERT( pParent->treeWidget() );
    18.  
    19. delete pItem; // mem leak
    20.  
    21. LOG("SafeDeleteOut" );
    22.  
    23. }
    To copy to clipboard, switch view to plain text mode 

    OUTPUT in log:

    22:55:23 SafeDelete Text: bob (2e25d20)
    22:55:23 index=1; ParentText: CorrectParentText
    22:55:23 Can We access pItem? bob CorrectParentText
    22:55:23 Can We access Parent? CorrectParentText
    22:55:23 Can We access pItem? bob CorrectParentText
    22:55:23 Debug assert failed on line 239 of testone.h.

    How can I access pItem->parent()->text(0), but then, the next line assert fails ON:
    ASSERT(!pItem->parent())

    I don't understand this.

    EDIT:
    If I remove the asserts, it goes by this function OUT... and then it comes back to this function again in the next item in the list... and crashes on the SECOND
    LOG("Can We access pItem? %s %s", Q2A( pItem->text(0) ), Q2A(pItem->parent()->text(0)));

    Like as if takeChild destroys the parent or something.
    Last edited by VireX; 1st June 2007 at 04:21.

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

    Default Re: Deleting from TreeWidget... Memoryleak

    What calls that "DeleteUser" method? How does the structure of the tree look like? Do those items really have parent items?

  5. #5
    Join Date
    Jan 2007
    Posts
    209
    Thanks
    34
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Deleting from TreeWidget... Memoryleak

    As you can see by the log data:

    22:55:23 SafeDelete Text: bob (2e25d20)
    22:55:23 index=1; ParentText: CorrectParentText
    22:55:23 Can We access pItem? bob CorrectParentText
    22:55:23 Can We access Parent? CorrectParentText
    22:55:23 Can We access pItem? bob CorrectParentText
    22:55:23 Debug assert failed on line 239 of testone.h.

    This means, that bob has a parent named CorrectParentText, and so I don't understand how an assert can fail, when it calls the parent() even though we just did it the line before, unless its some sort of weird bug in takeChild causing memory corruption or something.

    what the last two lines mean is this:
    pItem->parent()->text( 0 ); <--- no crash.
    pItem->parent() <--- crash.

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

    Default Re: Deleting from TreeWidget... Memoryleak

    Correct me if I'm wrong but it seems to me the behaviour is perfectly fine with what your code looks like. The thing you do is more or less like the following:
    1. find index of pItem which is child of pParent
    2. pParent->takeItem(pItem)
    3. access pItem->parent()
    4. app asserts

    The thing is that in (2) you remove the item from its parent, thus it doesn't have a parent anymore, therefore accessing the parent before (2) is fine, but after (2) causes the assert to fire because the parent is not valid anymore (it's null).

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
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.