基于Qt documentation,每当通过 Q_INVOKABLE 方法将 QObject 指针类型从C ++代码传递到QML时,就会有一组规则确定谁负责该指针的生命周期。如果 QObject 是无父的,则QML引擎隐式负责获取指针的所有权。
在我的场景中,我希望前端UI代表一个由后端C ++代码生成/提供的列表模型。我的假设是,只要QML代码对其进行了引用,该指针将保持活动状态。下面的代码显示了经过精简的测试用例:
Main.cpp
#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"
Main.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(销毁通过stdout中的“ Creation”和“ Destruction”输出显而易见)。
我很好奇为什么指针被破坏了?我注意到它没有将 ListView 设置为其父级,这很公平,我认为QML引擎会使用某种形式的引用指针来尝试跟踪谁仍然持有对它的引用。是否有文档可以更深入地了解垃圾收集/所有权的实现方式。
同样,有一种更好的方法来构造此代码,同时仍然满足将无父母的 QObject 传递回QML的要求。
答案 0 :(得分:-1)
破坏的原因似乎是因为该对象未在QML中引用,例如,如果将其分配给属性,则垃圾收集器将不会对其造成影响:
ApplicationWindow {
id: window
width: 200
height: 250
visible: true
property var mymodel: backend.createModel()
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: mymodel
delegate: Text {
anchors.horizontalCenter: parent.horizontalCenter
text: display
}
}
Button {
Layout.alignment: Qt.AlignCenter
text: qsTr("Garbage Collect")
onClicked: gc()
}
}
}