Delete of QObject in QList
-
Hi guys,
I'm a bit stuck at the moment and don't understand why my Qobject derived class is being deleted.Here's the problem:
I am using a generic ListModel from here: https://github.com/sgbo/QGenericListModel
This model is inherited from the "RecipeModel". It uses the "RecipeItem" as type. The RecipeItem only contains Q_PROPERTY for use in QML.class RecipeModel : public GenericListModel<RecipeItem> { Q_OBJECT public: explicit RecipeModel(QObject *parent = nullptr); ~RecipeModel() override; Q_INVOKABLE RecipeItem *at(int i); Q_INVOKABLE RecipeItem *at(const QString &name); signals: };
#include "recipemodel.h" RecipeModel::RecipeModel(QObject *parent) : GenericListModel(parent) { } RecipeModel::~RecipeModel() { qDebug() << Q_FUNC_INFO; } RecipeItem *RecipeModel::at(int i) { qDebug() << m_itemList.at(i); if(m_itemList.isEmpty()) return nullptr; return GenericListModel::at(i); } RecipeItem *RecipeModel::at(const QString &name) { return GenericListModel::at(name, "name"); }
The RecipeModel is initialised in the class "Core" and is kept over the runtime of the programm.
#ifndef CORE_H #define CORE_H #include <QObject> #include <QtQml> #include "corebase.h" class RecipeItem; class IRecipeItemDao; class RecipeDaoDatabase; class Core : public CoreBase { Q_OBJECT RecipeItem * m_currentItem; QSharedPointer<IRecipeItemDao> m_recipeItemDao; public: explicit Core(QObject *parent = nullptr); ~Core() override; Q_INVOKABLE RecipeItem * currentItem() const; void setCurrentItem(RecipeItem *item); Q_INVOKABLE void setCurrentItem(int modelIndex); QSharedPointer<IRecipeItemDao> recipeItemDao() const; }; #endif // CORE_H
So, now the crux:
If I get the "Item" from the model (with the function GenericListModel::at(int)), then the RecipeItem is deleted.
The next time I fetch it with "GenericListModel::at", the device crashes.
Can someone explain to me why?
Access from QML e.g:import QtQuick 2.4 import QtQuick.Window 2.3 import QtQuick.VirtualKeyboard 2.4 import Qt.labs.settings 1.1 import QtQml 2.12 import "../Content" import UserModule 1.0 import Backend 1.0 Item { id: appContainer width: Screen.width < Screen.height ? Screen.height : Screen.width height: Screen.width < Screen.height ? Screen.width : Screen.height rotation: Screen.width < Screen.height ? 90 : 0 property int listId: listId ReceipeCreateNewFormular { id: receipeCreateNew // RecipeModelController { // id: recipeModelController // core: CoreApp // } Component.onCompleted: { var item = CoreApp.recipeModel.at(listId) <<<--------------------- console.log(CoreApp.recipeModel.at(listId)) // recipeName.inputText = item.name // datetimeinput.inputText = item.date.toLocaleDateString(Qt.locale("de_DE"), Locale.ShortFormat) // mashWater.inputText = item.mashWater // spargeWater.inputText = item.spargeWater // gravity.inputText = item.origGravity // castWort.inputText = item.castWort // beerSort.inputText = item.beerSort // cookTime.inputText = item.cookTime // author.inputText = item.author // shortDescription.areatext = item.shortDescription // listHop.model = listItem.hopModel // listMash.model = listItem.mashModel } butTakeDataOver.onClicked: { // console.log("butTakeDataOver " + receipeCreateNew.recipeName.inputText); // recipeModelController.updateItem(listItem, // receipeCreateNew.recipeName.inputText, // Date(receipeCreateNew.datetimeinput.inputText), // receipeCreateNew.beerSort.inputText, // receipeCreateNew.author.inputText, // receipeCreateNew.castWort.inputText, // receipeCreateNew.gravity.inputText, // receipeCreateNew.shortDescription.areatext, // receipeCreateNew.mashWater.inputText, // receipeCreateNew.spargeWater.inputText, // receipeCreateNew.cookTime.inputText) // mainStackView.pop() } butAddMashStep.icon.source: MainConstants.getIconFile("content", "ic_add_circle_outline") butAddHopStep.icon.source: MainConstants.getIconFile("content", "ic_add_circle_outline") } InputPanel { id: inputPanel y: appContainer.height z: 99 anchors.left: parent.left anchors.right: parent.right states: State { name: "visible" when: inputPanel.active PropertyChanges { target: inputPanel y: appContainer.height - inputPanel.height } PropertyChanges { target: receipeCreateNew contentHeight: appContainer.height + inputPanel.height } } AutoScroller {} } }
Thanks for your help :)
-
@Krulle said in Delete of QObject in QList:
The next time I fetch it with "GenericListModel::at", the device crashes.
Use a debugger, see where it crashes. It for sure crashes when the list is empty in RecipeModel::at(int i)
-
@Krulle I see a
Q_INVOKABLE
for the at() function. This is for QML right?I bet that your RecipeModel or your RecipeItem's have no valid QObject parent. Thus the QMLengine takes ownership of those items and the GC mercilessly deletes them when your QML part doesn't use them any more.
Couple of options you have
- give them proper c++ parents
- use https://doc.qt.io/qt-5/qqmlengine.html#setObjectOwnership to explicitly set the ownership to c++
- make your non modifying getter functions, const functions <- this one is good practice anyway but I'm unsure if it will prevent the ownership steal, depends on the implementation I guess.
-
@J-Hilk said in Delete of QObject in QList:
@Krulle I see a
Q_INVOKABLE
for the at() function. This is for QML right?I bet that your RecipeModel or your RecipeItem's have no valid QObject parent. Thus the QMLengine takes ownership of those items and the GC mercilessly deletes them when your QML part doesn't use them any more.
Couple of options you have
- give them proper c++ parents
- use https://doc.qt.io/qt-5/qqmlengine.html#setObjectOwnership to explicitly set the ownership to c++
- make your non modifying getter functions, const functions <- this one is good practice anyway but I'm unsure if it will prevent the ownership steal, depends on the implementation I guess.
Thank you very much. You are right.
The parent object was a nullptr. After I passed a valid parent object to the RecipeItem, it was no longer deleted.