What are the post-processing operations after I manually delete QObject
-
qt's memory management does more than I imagined.
for example, in the following two examples, I manually deleted the
headerItem
, and thetreeWidget
called theheaderItem()
function and returned nullptr, indicating that thetreeWidget
knew that theheaderItem
was deleted, to ensure the security of the code.In the same way, if you manually delete a
validator
,lineEdit
will also return nullptr when you callvalidator()
.I'm curious about what post-processing operations are done after QObject is deleted.
Send a
QObject::destroyed()
signal to notify treeWidget, lineEdit? orQPointer
is used to encapsulate the pointer#include <QApplication> #include <QDebug> #include <QLineEdit> #include <QIntValidator> #include <QGridLayout> #include <QTreeWidget> #include <QTreeWidgetItem> int main(int argc, char *argv[]) { QApplication a(argc, argv); QTreeWidget* treeWidget = new QTreeWidget(); QTreeWidgetItem* headerItem= new QTreeWidgetItem(); treeWidget->setHeaderItem(headerItem); delete headerItem; qDebug()<<treeWidget->headerItem(); QLineEdit* lineEdit = new QLineEdit(); QIntValidator* validator = new QIntValidator(); lineEdit->setValidator(validator); delete validator; qDebug()<<lineEdit->validator(); }
With the example above, I found that qt memory management does more than I thought.
I'm trying to write a class that contains
QObject*
, it's important for me to know the official correct way to do it, if you know the inside story, please let me know, thanks -
qt's memory management does more than I imagined.
for example, in the following two examples, I manually deleted the
headerItem
, and thetreeWidget
called theheaderItem()
function and returned nullptr, indicating that thetreeWidget
knew that theheaderItem
was deleted, to ensure the security of the code.In the same way, if you manually delete a
validator
,lineEdit
will also return nullptr when you callvalidator()
.I'm curious about what post-processing operations are done after QObject is deleted.
Send a
QObject::destroyed()
signal to notify treeWidget, lineEdit? orQPointer
is used to encapsulate the pointer#include <QApplication> #include <QDebug> #include <QLineEdit> #include <QIntValidator> #include <QGridLayout> #include <QTreeWidget> #include <QTreeWidgetItem> int main(int argc, char *argv[]) { QApplication a(argc, argv); QTreeWidget* treeWidget = new QTreeWidget(); QTreeWidgetItem* headerItem= new QTreeWidgetItem(); treeWidget->setHeaderItem(headerItem); delete headerItem; qDebug()<<treeWidget->headerItem(); QLineEdit* lineEdit = new QLineEdit(); QIntValidator* validator = new QIntValidator(); lineEdit->setValidator(validator); delete validator; qDebug()<<lineEdit->validator(); }
With the example above, I found that qt memory management does more than I thought.
I'm trying to write a class that contains
QObject*
, it's important for me to know the official correct way to do it, if you know the inside story, please let me know, thanks@keeplearning Take a look at https://doc.qt.io/qt-6/objecttrees.html
If you delete a QObject it will also delete all its children. -
qt's memory management does more than I imagined.
for example, in the following two examples, I manually deleted the
headerItem
, and thetreeWidget
called theheaderItem()
function and returned nullptr, indicating that thetreeWidget
knew that theheaderItem
was deleted, to ensure the security of the code.In the same way, if you manually delete a
validator
,lineEdit
will also return nullptr when you callvalidator()
.I'm curious about what post-processing operations are done after QObject is deleted.
Send a
QObject::destroyed()
signal to notify treeWidget, lineEdit? orQPointer
is used to encapsulate the pointer#include <QApplication> #include <QDebug> #include <QLineEdit> #include <QIntValidator> #include <QGridLayout> #include <QTreeWidget> #include <QTreeWidgetItem> int main(int argc, char *argv[]) { QApplication a(argc, argv); QTreeWidget* treeWidget = new QTreeWidget(); QTreeWidgetItem* headerItem= new QTreeWidgetItem(); treeWidget->setHeaderItem(headerItem); delete headerItem; qDebug()<<treeWidget->headerItem(); QLineEdit* lineEdit = new QLineEdit(); QIntValidator* validator = new QIntValidator(); lineEdit->setValidator(validator); delete validator; qDebug()<<lineEdit->validator(); }
With the example above, I found that qt memory management does more than I thought.
I'm trying to write a class that contains
QObject*
, it's important for me to know the official correct way to do it, if you know the inside story, please let me know, thanks@keeplearning
Have you read Object Trees & Ownership?QObject
s have parent and children.
Documentation also talks about ownership, e.g.
void QTreeWidget::setHeaderItem(QTreeWidgetItem *item)The tree widget takes ownership of the item.
You should not be sending
QObject::destroyed()
signals. Delete the objects manually/automatically as appropriate. Qt will take care of the correct memory management, you should not need to know "the inside story". -
@keeplearning Take a look at https://doc.qt.io/qt-6/objecttrees.html
If you delete a QObject it will also delete all its children.@jsulm
I know that qt uses object trees for memory management. But what I'm curious about is that in the above example, the code is also safe after manually removing QObject.I'm trying to design a container to contain
QObject*
, here's my simplified code:class Item:public QObject{ Q_OBJECT // do something }; class ItemList:public QObject{ Q_OBJECT public: ItemList(){} void addItem(Item*); void removeItem(Item*); private: QList<Item*> list; }; void ItemList::addItem(Item* item){ if(item==nullptr){ return; } if(list.contains(item)){ return; } list.append(item); } void ItemList::removeItem(Item* item){ for(auto iter= list.begin();iter != list.end();iter++){ if(*iter==item){ list.erase(iter); } } }
When an
Item*
is manually deleted externally, the ItemList needs to know about this to avoid accessing the freed memory.I came up with two solutions to this:
- wrap the
Item*
withQPointer
inside the ItemList,This methodcould avoids accessing the freed memory, but the downside is that elements in QList are still there. - emit
destroyed
signal to notify the ItemList when the Item is deleted,This method could solve problem, but it adds a bit of time overhead.
this is why I want to know "the inside story".
Looking forward to your next reply
- wrap the
-
@jsulm
I know that qt uses object trees for memory management. But what I'm curious about is that in the above example, the code is also safe after manually removing QObject.I'm trying to design a container to contain
QObject*
, here's my simplified code:class Item:public QObject{ Q_OBJECT // do something }; class ItemList:public QObject{ Q_OBJECT public: ItemList(){} void addItem(Item*); void removeItem(Item*); private: QList<Item*> list; }; void ItemList::addItem(Item* item){ if(item==nullptr){ return; } if(list.contains(item)){ return; } list.append(item); } void ItemList::removeItem(Item* item){ for(auto iter= list.begin();iter != list.end();iter++){ if(*iter==item){ list.erase(iter); } } }
When an
Item*
is manually deleted externally, the ItemList needs to know about this to avoid accessing the freed memory.I came up with two solutions to this:
- wrap the
Item*
withQPointer
inside the ItemList,This methodcould avoids accessing the freed memory, but the downside is that elements in QList are still there. - emit
destroyed
signal to notify the ItemList when the Item is deleted,This method could solve problem, but it adds a bit of time overhead.
this is why I want to know "the inside story".
Looking forward to your next reply
@keeplearning said in What are the post-processing operations after I manually delete QObject:
the ItemList needs to know about this to avoid accessing the freed memory
Why? If ItemList just stores pointers in a list then I don't see any problems. Or do you want to do more inside ItemList? Are you dereferencing the pointers somewhere in ItemList?
- wrap the
-
@keeplearning said in What are the post-processing operations after I manually delete QObject:
the ItemList needs to know about this to avoid accessing the freed memory
Why? If ItemList just stores pointers in a list then I don't see any problems. Or do you want to do more inside ItemList? Are you dereferencing the pointers somewhere in ItemList?
@jsulm The
Item*
pointer inside the ItemList may be manually deleted outside of the ItemList. -
@jsulm The
Item*
pointer inside the ItemList may be manually deleted outside of the ItemList.@keeplearning That is clear. But what would be the problem then? As long as ItemList does not access the items nothing bad will happen, that is my point.
-
@keeplearning That is clear. But what would be the problem then? As long as ItemList does not access the items nothing bad will happen, that is my point.
@jsulm The ItemList I gave is a simplified example, and the ItemList may manipulate Item*, such as accessing objectName()
QString ItemList::getobjectByIndex(int index){ if(index>=0&&index<list.count()){ return list[i]->objectName(); // list[i] maybe deleted already }else{ return nullptr; } }
-
@jsulm The ItemList I gave is a simplified example, and the ItemList may manipulate Item*, such as accessing objectName()
QString ItemList::getobjectByIndex(int index){ if(index>=0&&index<list.count()){ return list[i]->objectName(); // list[i] maybe deleted already }else{ return nullptr; } }
@keeplearning You can prevent others from deleting Item by making Item destructor private and ItemList friend of Item:
class ItemList; class Item { Item() {} private: ~Item() {} friend ItemList; }; class ItemList { public: ItemList(){} ~ItemList() { for (Item* item : list) { delete item; } } void addItem() { list.append(new Item()); } Item* at(int index) { return list.at(index); } private: QList<Item*> list; };
Now, only ItemList can delete Item.
-
@keeplearning You can prevent others from deleting Item by making Item destructor private and ItemList friend of Item:
class ItemList; class Item { Item() {} private: ~Item() {} friend ItemList; }; class ItemList { public: ItemList(){} ~ItemList() { for (Item* item : list) { delete item; } } void addItem() { list.append(new Item()); } Item* at(int index) { return list.at(index); } private: QList<Item*> list; };
Now, only ItemList can delete Item.
@jsulm
I understand what you're doing, but your approach causes the Item to only be used inside the ItemList, I'm trying to achieve is that the Item can be used externally, and when the Item is deleted, the ItemList won't go wrong.As the example I gave at the beginning,
treeWidget->headerItem()
return nullptr and doesn't error when you deleteheaderItem
, andlineEdit->validator()
doesn't go wrong when you deletevalidator
.So I wonder what was done after
validator
was deleted, so thatlineEdit
could knowvalidator
was deleted.The method of implementing ItemList can be referred to in its practice.
-
@jsulm
I understand what you're doing, but your approach causes the Item to only be used inside the ItemList, I'm trying to achieve is that the Item can be used externally, and when the Item is deleted, the ItemList won't go wrong.As the example I gave at the beginning,
treeWidget->headerItem()
return nullptr and doesn't error when you deleteheaderItem
, andlineEdit->validator()
doesn't go wrong when you deletevalidator
.So I wonder what was done after
validator
was deleted, so thatlineEdit
could knowvalidator
was deleted.The method of implementing ItemList can be referred to in its practice.
@keeplearning said in What are the post-processing operations after I manually delete QObject:
So I wonder what was done after validator was deleted, so that lineEdit could know validator was deleted.
Since those are all QObjects it's easy - the other classes simply connect to QObject::destroyed().
But tbh it really depends on what you want to do with that items. Do you even need to store them as pointer?