根据 Qt文档,每当QObject指针类型通过Q_INVOKABLE方法从 C++ 代码传递到 QML 时,都有一组规则确定谁负责该指针的生命周期。如果QObject是无父对象,则 QML 引擎隐含地负责获取指针的所有权。
在我的场景中,我希望我的前端 UI 表示由后端 C++ 代码生成/提供的列表模型。我的假设是,只要 QML 代码引用它,指针就会保持活动状态。下面的代码显示了精简的测试用例:
主文件
#include <QAbstractItemModel>
#include <QDebug>
#include <QGuiApplication>
#include <QObject>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QStringListModel>
class MyStringListModel : public QStringListModel
{
Q_OBJECT
public:
explicit MyStringListModel(const QStringList &strings, QObject* parent=nullptr) : QStringListModel(strings, parent)
{
qDebug() << "Creation";
}
virtual ~MyStringListModel() override
{
qDebug() << "Destruction";
}
};
class Backend : public QObject
{
Q_OBJECT
public:
Backend(QObject* parent=nullptr) : QObject(parent)
{
}
Q_INVOKABLE QAbstractItemModel* createModel() const
{
static const QStringList months = {
tr("January"),
tr("February"),
tr("March"),
tr("April"),
tr("May"),
tr("June"),
tr("July"),
tr("August"),
tr("September"),
tr("October"),
tr("November"),
tr("December"),
};
return new MyStringListModel(months);
}
};
int main(int argc, char* argv[])
{
QGuiApplication application(argc, argv);
qmlRegisterType<QAbstractItemModel>();
Backend backend;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("backend", &backend);
engine.load("qrc:///ui/main.qml");
return application.exec();
}
#include "main.moc"
主.qml
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.1
ApplicationWindow {
id: window
width: 200
height: 250
visible: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: backend.createModel()
delegate: Text {
anchors.horizontalCenter: parent.horizontalCenter
text: model.display
}
}
Button {
Layout.alignment: Qt.AlignCenter
text: qsTr("Garbage Collect")
onClicked: gc()
}
}
}
这是程序的截图:
用户单击按钮的那一刻,垃圾收集器运行并销毁模型 ptr(通过标准输出中的“创建”和“销毁”输出可以看出销毁)。
我很想知道为什么指针被破坏了?我注意到它没有将ListView设置为其父级,这很公平,我认为 QML 引擎会使用某种形式的引用指针来尝试跟踪谁仍然持有对它的引用。是否有文档可以更深入地了解垃圾收集/所有权的实施方式。
同样,是否有更好的方法来构建此代码,同时仍满足将无父QObject传递回 QML 的要求。