Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

memory management



  • hello,

    In one QObject derived class I have a loop where i dinamically create Obj objects (QObject derived) , set attributes and add them to a member container (QVariantList) using QVariant::fromValue

    myObjectList.clear() // QVariantList
    // loop
    Obj*o = new Obj(this); //             
    o->setValue(6);
    myObjectList.append(QVariant::fromValue(o)); // myObjectList is a  QVariantList  type member variable
    // endloop
    emit myObjectListChanged()
    

    every time i enter this method/loop i need to empty myObjectList and re-create the Obj objects to store them back in my list.

    But calling myObjectList.clear() will not delete the Obj* objects ? is that right?
    Obj objects will only be deleted when this is deleted because i create them like this Obj*o = new Obj(this); ?

    thank you


  • Lifetime Qt Champion

    @ODБOï said in memory management:

    But calling myObjectList.clear() will not delete the Obj* objects ? is that right?

    Yes

    You can use https://doc.qt.io/qt-5/qtalgorithms.html#qDeleteAll-1


  • Moderators

    @jsulm does QVariant::fromValue return a copy of the pointer in this case ? and is there an implicit back conversion ?
    Or does calling delete on a Variant from a pointer actually call delete on the pointer and not on the QVariant !?

    Lots of magic going on here 🙈


  • Lifetime Qt Champion

    @J-Hilk Good question. I'm not sure. But this can be easily tested with a debug output in Obj destructor :-)


  • Qt Champions 2017

    @ODБOï said in memory management:

    But calling myObjectList.clear() will not delete the Obj* objects ? is that right?

    Yes.

    Obj objects will only be deleted when this is deleted because i create them like this Obj*o = new Obj(this); ?

    Or explicitly, or via a signal-slot connection, but yes.

    @J-Hilk said in memory management:

    does QVariant::fromValue return a copy of the pointer in this case ?

    It does.

    and is there an implicit back conversion ?

    I don't believe so. Back convert to what? QObject *, void *, int *?

    Or does calling delete on a Variant from a pointer actually call delete on the pointer and not on the QVariant !?

    You can test this, but as QVariant or any other Qt type I'm aware of doesn't overload the delete operator I imagine you're going to get a compile-time error.


  • Qt Champions 2017

    @ODБOï
    Something I forgot to ask, why not keep the object list as a regular one (e.g. QList<QObject *>) and put the QVector/QList in the variant whenever you need to?


  • Moderators

    ok, ok, I see 😜

    I'll go and test it myself...

    class MyObj : public QObject
    {
        Q_OBJECT
    public:
        explicit MyObj (QObject *parent = nullptr) : QObject(parent){}
        ~MyObj() {
            qDebug("Destroy ME!!!!");
        }
    };
    
    
    int main(int argc, char *argv[])
    {
    
        Q_UNUSED(argc);
        Q_UNUSED(argv);
    
        QVariantList myVariantList;
    
        for(int i{0},j{10}; i < j; i++)
            myVariantList.append(QVariant::fromValue(new MyObj()));
    
        qDeleteAll(myVariantList);
        qDebug("End of main");
    //    QApplication app(argc, argv);
    //    return a.exec();
    }
    
    #include "main.moc"
    

    results int he compiler error: cannot delete expression of type 'const QVariant'

    Well, so we'll have to use our own deleteall. One that also clears, as that is what we actually want. Delete & Clear:

    class MyObj : public QObject
    {
        Q_OBJECT
    public:
        explicit MyObj (QObject *parent = nullptr) : QObject(parent){}
        ~MyObj() override {
            qDebug("Destroy ME!!!!");
        }
    };
    
    template <typename Class>
    inline void deleteAllAndClear(QVariantList &list)
    {
        for(const QVariant &v : list){
            delete  qvariant_cast<Class*>(v);
        }
        list.clear();
    }
    
    int main(int argc, char *argv[])
    {
    
        Q_UNUSED(argc)
        Q_UNUSED(argv)
    
        QVariantList myVariantList;
    
        for(int i{0},j{10}; i < j; i++)
            myVariantList.append(QVariant::fromValue(new MyObj()));
    
        qDebug() << "size of list" << myVariantList.size();
    
        deleteAllAndClear<MyObj>(myVariantList);
    
        qDebug() << "size of list" << myVariantList.size();
    
        qDebug("End of main");
    //    QApplication app(argc, argv);
    //    return a.exec();
    }
    
    #include "main.moc"
    

    Output:

    size of list 10
    Destroy ME!!!!
    Destroy ME!!!!
    Destroy ME!!!!
    Destroy ME!!!!
    Destroy ME!!!!
    Destroy ME!!!!
    Destroy ME!!!!
    Destroy ME!!!!
    Destroy ME!!!!
    Destroy ME!!!!
    size of list 0
    End of main



  • hi
    Thank you very much for all your inputs

    @kshegunov said in memory management:

    Something I forgot to ask, why not keep the object list as a regular one (e.g. QList<QObject *>) and put the QVector/QList in the variant whenever you need to?

    You are right it much simpler to have a member QList<QObject *> and return QVariant list only when i need it.
    Thats what i did.

    Thank you


Log in to reply