Results 1 to 13 of 13

Thread: QML failing to detect QObject destroyed in C++

  1. #1
    Join Date
    Jun 2012
    Posts
    58
    Thanks
    13
    Qt products
    Qt4

    Question QML failing to detect QObject destroyed in C++

    The presented code does the following:
    <1> Create object of QObject derived class and expose it to QML
    <2> The class has a pointer to another QObject derived class and the pointer is accessible to QML via Q_PROPERTY.
    <3> MouseArea in QML detects user-click and simply asks the c++ code for the pointer to be deleted.
    <4> Color of rectangle turns black once this is detected.

    The problem is that while certain approaches detect the deletion of the pointer by c++ other approaches don't.

    Look at the inline comments:
    Combination of (1) and (1b) works
    Combination of (1) and (1d) does not work
    (2) alone by itself works but (3) alone by itself does not.

    When things work you should see the color of the Rectangle turn to black from yellow.

    Can someone please explain this behaviour?

    CPP Code:
    Qt Code:
    1. class Name : public QObject
    2. {
    3. Q_OBJECT
    4. Q_PROPERTY(bool boolVal READ boolVal CONSTANT FINAL)
    5. public:
    6. bool boolVal() const {return true;}
    7. };
    8.  
    9. class Root : public QObject
    10. {
    11. Q_OBJECT
    12. Q_PROPERTY(QObject* name READ name CONSTANT FINAL)
    13. public:
    14. QObject* name() const {return m_pName;}
    15. Q_INVOKABLE void deleteName() {delete m_pName; m_pName = 0;}
    16. private:
    17. Name *m_pName {new Name};
    18. };
    19.  
    20. int main(int argc, char *argv[])
    21. {
    22. QGuiApplication app(argc, argv);
    23.  
    24. Root objRoot;
    25. QtQuick2ApplicationViewer viewer0;
    26. viewer0.rootContext()->setContextProperty("objRoot", &objRoot);
    27. viewer0.setMainQmlFile(QStringLiteral("qml/myApp/main.qml"));
    28. viewer0.showExpanded();
    29.  
    30. return app.exec();
    31. }
    To copy to clipboard, switch view to plain text mode 
    QML Code:
    Qt Code:
    1. import QtQuick 2.0
    2.  
    3. Rectangle {
    4. width: 360
    5. height: 360
    6.  
    7. color: "red"
    8.  
    9. Rectangle {
    10. id: objRect
    11. anchors {left: parent.left; top: parent.top}
    12. height: 70; width: 70;
    13.  
    14. property bool checked
    15. property QtObject temp: objRoot.name
    16.  
    17. color: checked ? "yellow" : "black" // (1)
    18.  
    19. //color: objRect.temp && objRect.temp.boolVal ? "yellow" : "black" //--->WORKS (2)
    20. //color: objRoot.name && objRoot.name.boolVal ? "yellow" : "black" //--->DOES NOT WORK !!! (3)
    21.  
    22. Binding on checked {
    23. //value: objRect.temp && objRect.temp.boolVal //--->DOES NOT WORK !!! (1a)
    24. //value: objRect.temp !== null && objRect.temp.boolVal //--->WORKS (1b)
    25. value: objRect.temp ? objRect.temp.boolVal : false //--->WORKS (1c)
    26.  
    27. //Using directly without collecting in local QtQobject temp:
    28. //----------------------------------------------------------
    29. //value: objRoot.name && objRoot.name.boolVal //--->DOES NOT WORK !!! (1d)
    30. //value: objRoot.name !== null && objRoot.name.boolVal //--->DOES NOT WORK !!! (1e)
    31. //value: objRoot.name ? objRoot.name.boolVal : false //--->DOES NOT WORK !!! (1f)
    32. }
    33.  
    34. Text {
    35. text: "Destroy"
    36. anchors.centerIn: parent
    37. }
    38.  
    39. MouseArea {
    40. anchors.fill: parent
    41. onClicked: objRoot.deleteName()
    42. }
    43. }
    44. }
    To copy to clipboard, switch view to plain text mode 

    {Qt/QML 5.2.0, Win 7, MinGW 4.8, QtQuick 2.0}

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QML failing to detect QObject destroyed in C++

    The problem is a wrong property declaration and a missing change signal emit.

    Qt Code:
    1. Q_PROPERTY(QObject* name READ name CONSTANT FINAL)
    To copy to clipboard, switch view to plain text mode 
    CONSTANT here is clearly wrong since the name object can change.
    The property declaration needs a NOTIFY signal that is emitted when that happens.

    Qt Code:
    1. Q_INVOKABLE void deleteName() {delete m_pName; m_pName = 0;}
    To copy to clipboard, switch view to plain text mode 
    This changes the name property but does not emit a change signal. Needs to emit the signal specified as the NOTIFY signal of the name property.

    Cheers,
    _

  3. #3
    Join Date
    Jun 2012
    Posts
    58
    Thanks
    13
    Qt products
    Qt4

    Default Re: QML failing to detect QObject destroyed in C++

    Hello anda_skoa,

    I was afraid m_pName = 0; would make it look like I'm explicitly changing the pointer and not notifying about it. This is not what is happening. I just wrote that to make double deletions in this contrived example not crash.

    You can remove m_pName = 0; part. The code will still behave the same. What is implied here is that m_pName is not being changed. delete m_pName will do nothing to m_pName (nothing happens to the pointer, only the pointee will be destructed). Still delete m_pName is detected by QML in certain scenarios and not in other. I suspect from experimenting that this detection has nothing to do with the way user codes. If QObject* from c++ is bound to some property QtObject someName in QML then there is a silent connection being made with the c++ QObject's destroyed signal. That way whenever the QObject is destroyed in c++ through any mechanism the corresponding someName also becomes null (though no one explicitly made anything null - pointers are still pointing to the same location in the memory although a destroyed/reclaimed one).

    Are all these assumptions right?

    Here is something simpler to support my assumption:
    before and after the call to objRoot.deleteName() in MouseArea's click handler in the code give try to consol.log(objRect.temp, objRoot.name). You will get valid memory address before the call and null after the call for both of them.

    How does this happen? No one has explicity changed the content of the pointer in c++?

    It would be a great help if you can help me figure this out as it is a major conceptual mystery right now in my project.

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QML failing to detect QObject destroyed in C++

    Quote Originally Posted by ustulation View Post
    I was afraid m_pName = 0; would make it look like I'm explicitly changing the pointer and not notifying about it. This is not what is happening. I just wrote that to make double deletions in this contrived example not crash.
    I was not commenting about the resetting of the pointer to 0, I was referring to the deletion.
    Your property declaration claims that the property will not change (CONSTANT), but it does (the object gets deleted) and there is no NOTIFY that makes the QML engine aware of the change.

    Obviously you want to do the reset otherwise any read of the property would return an invalid pointer after the delete has happend.

    Once you have fixed the C++ code, the QML code will work as expected.

    Cheers,
    _

  5. #5
    Join Date
    Jun 2012
    Posts
    58
    Thanks
    13
    Qt products
    Qt4

    Default Re: QML failing to detect QObject destroyed in C++

    I do understand your point.However I think if you explain me this, it will clarify things for me.

    Very Simple Code:

    CPP:
    Qt Code:
    1. class Name : public QObject {Q_OBJECT};
    2.  
    3. class Root : public QObject
    4. {
    5. Q_OBJECT
    6. Q_PROPERTY(QObject* name READ name NOTIFY nameChanged)
    7. public:
    8. QObject* name() const {return m_pName;}
    9. Q_INVOKABLE void deleteName() {delete m_pName; emit nameChanged();}
    10. Q_SIGNAL void nameChanged();
    11.  
    12. private:
    13. Name *m_pName {new Name};
    14. };
    To copy to clipboard, switch view to plain text mode 
    QML: (of-course Root is available to QML via setContextProperty as objRoot)
    Qt Code:
    1. import QtQuick 2.0
    2.  
    3. Rectangle {
    4. width: 360
    5. height: 360
    6. color: "red"
    7.  
    8. Rectangle {
    9. id: objRect
    10. anchors {left: parent.left; top: parent.top}
    11. height: 70; width: 70; color: "blue"
    12.  
    13. Text {text: "Destroy"; anchors.centerIn: parent}
    14.  
    15. MouseArea {
    16. id: idMA0
    17. anchors.fill: parent
    18. onClicked: {
    19. console.log(objRoot.name);
    20. objRoot.deleteName();
    21. console.log(objRoot.name);
    22. enabled = false
    23. }
    24. }
    25. }
    26. }
    To copy to clipboard, switch view to plain text mode 
    And this is the output:
    Qt Code:
    1. Name(0x180cf5c0)
    2. null
    To copy to clipboard, switch view to plain text mode 

    How did null get printed? I did not assign null ptr to m_pName anywhere. If I print the content of m_pName in c++ I'll still get 0x180cf5c (i've verified this). And all this happens irrespective of whether emit nameChanged() is done or not. (this too can easily be verified by removing the emit).

    How is QML being informed of the destruction? Is there nothing hidden going on? Like QObject's destroyed signal being monitored etc?

  6. #6
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QML failing to detect QObject destroyed in C++

    The second console.log reads the property again. No idea why it does not crash though, the C++ code is obviously still wrong as it leaves a dangling pointer.

    I am afraid I don't understand what your objectives are. The solution to the original problem is to notify about the change and make sure the returned QObject is valid or 0.

    Qt Code:
    1. Q_INVOKABLE void deleteName() {delete m_pName; m_pName = 0; emit nameChanged();}
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

  7. The following user says thank you to anda_skoa for this useful post:

    ustulation (30th June 2014)

  8. #7
    Join Date
    Jun 2012
    Posts
    58
    Thanks
    13
    Qt products
    Qt4

    Default Re: QML failing to detect QObject destroyed in C++

    The solution to the original problem is to notify about the change and make sure the returned QObject is valid or 0.
    I agree to this. This will always work.

    No idea why it does not crash though
    This is what I want to know. The null is detected by the QML on every platform (Win 7, Mac, Debian) and in every program ranging from small to big I have tried so far. I need to understand if it is through design that this null detection is propagated to QML. I've tried it in so many ways but the null detection always works. This makes it convincing that it is not through chance or luck that this is happening but due to some consistent behavior. There is no need to emit signals, there is no need to do anything. Emission of signals etc is required if the pointer starts pointing to another valid QObject - ie., assigned to another object. In this case it is a must and nothing happens in QML if you don't emit signals which is understandable because this is how Q_PROPERTY for other types (int, bool etc) work too. But Q_PROPERTY for QObject* continues to baffle me for cases involving deletion.

    This I need to know.

  9. #8
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QML failing to detect QObject destroyed in C++

    Quote Originally Posted by ustulation View Post
    need to understand if it is through design that this null detection is propagated to QML. I've tried it in so many ways but the null detection always works.
    My guess would be that the property binding connects not only to the change signal but if the returned type is a QObject subclass then also to the object's destroyed signal.

    Might be better if it did not as it can, as we have seen here, hide incorrect property code.

    Quote Originally Posted by ustulation View Post
    Emission of signals etc is required if the pointer starts pointing to another valid QObject - ie., assigned to another object.
    Emission of the signal is required if the property changes, i.e. if bindings using that property should be reevaluated.
    Which is usually when the property's value changes.
    Like in your case, then the object becomes invalid.

    Cheers,
    _

  10. The following user says thank you to anda_skoa for this useful post:

    ustulation (30th June 2014)

  11. #9
    Join Date
    Jun 2012
    Posts
    58
    Thanks
    13
    Qt products
    Qt4

    Default Re: QML failing to detect QObject destroyed in C++

    Might be better if it did not as it can...
    To the contrary I think it is a very good thing. You cannot always know about the deletion. Consider this case:
    Right now class Root has class Name exposed via Q_PROPERTY in above code. Assume this continues: class Name exposes class Name1 which in turn has class Name2 which in turn has class Name3 and each one is created by the parent by passing the "this" pointer for Qt's memory management. In QML you do something like:

    property QtObject objName3: objRoot.name.name1.name2.name3

    Now in C++ somewhere you do
    delete m_pName;

    Qt's parent-child memory manangement will ensure that the entire chain gets deleted all the way upto Name3 pointer contained in class Name2. How would you let the QML objName3 above know of this? It will become difficult to track and will restrict coding approaches. If the detection is automatic like it is in all the examples I've tried so far then it makes very good sense for QML.

    QML thus makes objName3 null as can easily be verified.

    What are your thought?

    My guess would be that the property binding connects not only to the change signal but if the returned type is a QObject subclass then also to the object's destroyed signal
    Exactly! This is what i was saying all along. The difference is that while you are guessing, I was convinced and have coded thinking this is how it works. And that is what is scaring me right now

    Can you confirm you guess?

  12. #10
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QML failing to detect QObject destroyed in C++

    Quote Originally Posted by ustulation View Post
    property QtObject objName3: objRoot.name.name1.name2.name3

    Now in C++ somewhere you do
    delete m_pName;
    The notification signal would tell QML that the value of the name property has changed, so it will update all bindings.
    Thus it would read "name" again, encounter 0 (assuming a proper implementation of the delete method as discussed earlier).
    It would not attampt to access any of the sub properties, the binding would evaluate to "undefined".

    Cheers,
    _

  13. #11
    Join Date
    Jun 2012
    Posts
    58
    Thanks
    13
    Qt products
    Qt4

    Default Re: QML failing to detect QObject destroyed in C++



    Ok.. what about this:

    Qt Code:
    1. property QtObject objName3
    2. Component.onCompleted: objName3 = objRoot.name.name1.name2.name3
    To copy to clipboard, switch view to plain text mode 

    and as usual in c++:
    Qt Code:
    1. delete m_pName;
    To copy to clipboard, switch view to plain text mode 

    Try to console.log(objName3) before and after deletion. You will still get null. There is no binding involved now for any notifiers to notify. How would things work now?

    My guess would be that the property binding connects not only to the change signal but if the returned type is a QObject subclass then also to the object's destroyed signal
    Exactly! This is what i was saying all along. The difference is that while you are guessing, I was convinced and have coded thinking this is how it works. And that is what is scaring me right now

    Can you confirm you guess?
    If you can do this, i suppose things will be clear then.

    P.S: I'm very grateful that you are investing time in helping me solve my problem. I hope something good will come out at the end of all this for everyone

  14. #12
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QML failing to detect QObject destroyed in C++

    Quote Originally Posted by ustulation View Post


    Ok.. what about this:

    Qt Code:
    1. property QtObject objName3
    2. Component.onCompleted: objName3 = objRoot.name.name1.name2.name3
    To copy to clipboard, switch view to plain text mode 

    and as usual in c++:
    Qt Code:
    1. delete m_pName;
    To copy to clipboard, switch view to plain text mode 

    Try to console.log(objName3) before and after deletion. You will still get null. There is no binding involved now for any notifiers to notify. How would things work now?
    I am afraid I don't understand the question. The two log write will retrieve the property individually, if the value changes in between then the two values will be different.

    No change signal involved but two reads of the property nevertheless.


    Quote Originally Posted by ustulation View Post
    If you can do this, i suppose things will be clear then.
    Every Qt installation comes with the Qt source code

    Cheers,
    _

  15. #13
    Join Date
    Jun 2012
    Posts
    58
    Thanks
    13
    Qt products
    Qt4

    Default Re: QML failing to detect QObject destroyed in C++

    The two log write will retrieve the property individually, if the value changes in between then the two values will be different.
    No. Not from the reader function in c++ if you meant that. Just to be sure i put std::cerr over there like this:

    Qt Code:
    1. QObject* name3() const { std::cerr << "Property read." << std::endl; return m_pName3;}
    To copy to clipboard, switch view to plain text mode 

    And this i have put everywhere in all classes involved. Reading QML's objName3 will never invoke any property reader function written in c++. That is the difference between for instance:

    Qt Code:
    1. property QtObject objName
    2. Component.onCompleted: objName = objRoot.name
    To copy to clipboard, switch view to plain text mode 

    and somewhere else:
    Qt Code:
    1. console.log(objRoot.name) //--> this WILL invoke the c++ property reader function
    2. console.log(objName) //--> this WILL NEVER inovke the property reader function
    To copy to clipboard, switch view to plain text mode 
    and further if you have:
    Qt Code:
    1. onObjNameChanged: console.log(objName)
    To copy to clipboard, switch view to plain text mode 

    you will see it being printed when Component.onCompleted above assigned to it, which is understandable and everyone agrees BUT also when delete m_pName in c++ is done. In this case onObjNameChanged will be called again and will print null.

    I hope i have been able to describe it properly this time.

    Every Qt installation comes with the Qt source code
    hehe..i consider myself too much of a newbie to do that.

Similar Threads

  1. Doing work after QML item is destroyed
    By pherthyl in forum Qt Quick
    Replies: 4
    Last Post: 16th February 2014, 16:33
  2. QWaitCondition: Destroyed while threads are still waiting
    By TimShnaider in forum Qt Programming
    Replies: 1
    Last Post: 22nd July 2012, 03:07
  3. Destroyed while process is still running
    By qtzcute in forum Qt Programming
    Replies: 5
    Last Post: 23rd July 2009, 09:26
  4. Object destroyed, what about connections?
    By Caius Aérobus in forum Qt Programming
    Replies: 1
    Last Post: 7th July 2008, 18:41
  5. [Qt 4.1.3] Child widget not destroyed
    By Dusdan in forum Qt Programming
    Replies: 13
    Last Post: 24th May 2006, 09:17

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.