Quitting, assert runtime error - child, parent



  • Dear all,

    I'm working on a desktop client monitoring a wind turbine.
    I am programming components in c++ that creates QQmlComponent from a .qml file and then creates a QObject and link it with my window's content Rectangle.

    When i call Qt.quit() from the QML, i have a runtime error and don't really know from where it is coming.
    I thought i was from the parent - child link but nothing resolved it.

    What do you think of that ?
    Is there somebody having the same issue ? (I found nothing or nothing helping on google so i think i made something wrong that is evident to Qt programmers).

    Error :

    ASSERT: "childItems.contains(child)" in file items\qquickitem.cpp, line 2953
    Invalid parameter passed to C runtime function.
    Invalid parameter passed to C runtime function.
    ASSERT: "!m_thread.isRunning()" in file qqmldebugserver.cpp, line 655
    Invalid parameter passed to C runtime function.
    Invalid parameter passed to C runtime function.
    

    Some time this error is replaced by the CoreIndex >= 0 assert

    LogInForm.h

    #ifndef LOGINFORM_H
    # define LOGINFORM_H
    
    # include <QObject>
    # include <QQmlComponent>
    # include <QQmlEngine>
    # include <QUrl>
    # include <QQuickItem>
    # include <QtQuick>
    # include <QQuickItem>
    # include <iostream>
    
    class LogInForm : public QObject
    {
        Q_OBJECT
    public:
    
        // Constructor
        explicit LogInForm(QObject *parent = 0, QQmlEngine *engine = 0);
    
    signals:
    
    public slots:
    
    protected slots:
        void onViewStatusChanged(QQmlComponent::Status status);
        void onSubmitForm();
    
    protected:
        QString         _qmlSrcUrl;
        QQmlEngine      *_engine;
        QQmlComponent   *_component;
        QObject         *_qmlComponent;
    };
    
    #endif // LOGINFORM_H
    
    

    LogInForm.cpp

    #include "cpp/headers/qtViews/loginform.h"
    
    LogInForm::LogInForm(QObject *parent, QQmlEngine *engine) : QObject(parent)
    {
        // Set the QML Source File Path/Url
        _qmlSrcUrl = "qrc:/qml/logInForm.qml";
    
        // Get the QQmlEngine
        if (engine != 0){
            _engine = engine;
        } else {
            _engine = new QQmlEngine();
        }
    
        // Create a QQmlComponent Object from QML Source File
        _component = new QQmlComponent(_engine, QUrl(_qmlSrcUrl));
    
        std::cout << _component->status() << std::endl;
        QList<QQmlError> errors = _component->errors();
        foreach (QQmlError e, errors) {
            std::cout << "(" << e.line() << ", " << e.column() << ") :: " << qPrintable(e.description()) << std::endl << qPrintable(e.toString()) << std::endl;
        }
        // Track when the component is ready
        if(_component->status() == QQmlComponent::Ready)
        {
            onViewStatusChanged(QQmlComponent::Ready);
        } else {
            connect(_component, SIGNAL(statusChanged(QQmlComponent::Status)),
               this, SLOT(onViewStatusChanged(QQmlComponent::Status)));
        }
    }
    
    void LogInForm::onViewStatusChanged(QQmlComponent::Status status)
    {
        QQuickItem *i = Q_NULLPTR;
        if(status == QQmlComponent::Ready)
        {
            // Create a Qml Object from the created _component
            _qmlComponent = _component->create();
    
            i = qobject_cast<QQuickItem*>(_qmlComponent);
    
            // Set Cpp ownership to avoid javascript garbage collector to delete the object
            QQmlEngine::setObjectOwnership(i, QQmlEngine::CppOwnership);
    
            // Set parent and visual parent
            i->setParentItem(qobject_cast<QQuickItem*>(this->parent()));
            //i->setVisible(true);
            connect( _qmlComponent, SIGNAL(submitForm()), this, SLOT(onSubmitForm()));
        }
    }
    
    
    void LogInForm::onSubmitForm() {
        QString username = _qmlComponent->property("username").toString();
        QString password = _qmlComponent->property("password").toString();
        QString serverAddress = _qmlComponent->property("serverAddress").toString();
        QString serverName = _qmlComponent->property("serverName").toString();
    
    }
    
    

    Main.cpp

    #include <QApplication>
    #include <QQmlApplicationEngine>
    #include "cpp/headers/qtViews/loginform.h"
    #include <iostream>
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
    
        QObject *mainWindow = engine.rootObjects().first();
        if (!mainWindow){
            std::cerr << "Main :: mainWindow not found !" << std::endl;
            return EXIT_FAILURE;
        }
    
        QObject *contentRectangle = mainWindow->findChild<QObject*>("contentRectangle");
        if (!contentRectangle){
            std::cerr << "Main :: contentRectangle not found !" << std::endl;
            return EXIT_FAILURE;
        }
        QObject *logInForm = new LogInForm(contentRectangle, &engine);
    
        return app.exec();
    }
    
    

    Thank you a lot for helping,
    Olivier :)


  • Moderators

    To avoid errors in future, I strongly recommend setting all pointers to nullptr in your header or contructor initializer list. It's not a problem here, but it can quickly become one as the code evolves. Or use smart pointers.

    This is unusual way of creating QML interfaces, but looks very cool! :-)

    Regarding the errors - I have to say up front that I don't know the answer. I have only a few suspicions, but nothing certain:

    • object ownership: QObjects delete their children when they are deleted. _qmlComponent's visual parent is contentRectangle, but it's QObject parent seems to be the _component. Not sure if that is entirely correct
    • check if all the objects live in the same thread (with QObject::thread() or was it threadId()?) - maybe that will point you towards the problem
    • are you 100% sure that contentRectangle is a QQuickItem? You don't verify if the cast works in LogInForm::onViewStatusChanged
    • childItems.contains(child) LogInForm is a child of contentRectangle, and so is the _qmlComponent, but only only one of these is a QQuickItem. Maybe the parent object has a problem with that?
    • try running it via thread sanitizer and address sanitizer, maybe they will show mor eprecisely what fails


  • main.qml - What is the top level item ? Is it window or Item ?
    loginform.qml - What is top level item ? Is it window or Item ?

    This is typical issue of object deleted already is getting delete due to parent child relation ship ?



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.