【发布时间】:2018-08-07 14:49:24
【问题描述】:
我有一个 C++ 类,它在 QML 中作为产生其他类型的单例公开
qmlRegisterSingletonType<DomainManager>("my.pkg", 1, 0, "DomainManager", domain_provider);
qmlRegisterUncreatableType<Control>("my.pkg", 1, 0, "Control", "Get it fresh from DomainManager");
DomainManager 有一个功能
Q_INVOKABLE Control* controlWriter(QString partition);
根据http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#data-ownership,从Q_INVOKABLE 返回的对象归QML 所有,应该由GC 删除。唯一的例外似乎是在返回的对象上设置了父级时,情况并非如此。
我有一个StackView,其中包含具有属性的面板:
property Control ctrl: DomainManager.controlWriter(dummy.name)
我已经验证,当我将面板从堆栈中弹出时,Component.onDestruction 会被调用,因此面板确实会被删除。
但是,我在 C++ 对象上放置了以下析构函数,并且在整个应用程序退出之前它不会被删除。
~Control() { qDebug() << "deleting control"; };
我发现摆脱Control 对象的唯一方法是在Component.onDestruction 中调用ctrl.destroy() 以手动释放它。
为什么 QML 不释放这个对象?
包含该属性的完整 QML 文件如下。 ctrl 不在此文件之外使用。
import QtQuick 2.11
import my.pkg 1.0
Image {
id: dummy
property string name
property Control ctrl: DomainManager.controlWriter(dummy.name)
source: "dummy.jpg"
fillMode: Image.PreserveAspectFit
Connections {
target: gamepad
onAxisLeftYChanged: {
ctrl.id = dummy.name
ctrl.x = gamepad.axisLeftY * 32767
ctrl.yaw = gamepad.axisLeftX * 32767
ctrl.publish()
}
onAxisLeftXChanged: {
ctrl.id = dummy.name
ctrl.x = gamepad.axisLeftY * 32767
ctrl.yaw = gamepad.axisLeftX * 32767
ctrl.publish()
}
}
Component.onDestruction: {
// not sure why this requires manual clean-up
ctrl.destroy()
}
}
【问题讨论】:
-
在我的例子中 QML 确实删除了 Control 对象,在下面的链接中你可以找到我的测试项目github.com/eyllanesc/stackoverflow/tree/master/51729672
-
当对象作为方法调用的返回值返回给 QML 时,如果没有剩余的 JavaScript 对它的引用并且它没有 QObject::,QML 将跟踪它并删除它parent()。 但看起来 Qt 在 QML 引擎删除之前不会释放对象。
-
@eyllanesc 我向您的代码提交了一个 PR,以证明当您将属性设置为 null 时,它不会清理对象。
-
@Pepijn 该问题是由于您丢失了指针的位置而引起的,QML 将尝试清理存储在 ctrl 中的指针,并且在您的情况下,您已将其设置为 null。因此,您现在有责任这样做。
-
@Pepijn 就像这样做:
Control * ctrl = new Control; ctrl = nullptr; delete ctrl;指针丢失,因为 delete 删除了存储在 ctrl 中的引用。 delete 删除指针所指的变量。