QML QQmlPropertyList - 包含 object 个生命周期和 'memory rules'
QML QQmlPropertyList - contained object lifetimes and 'memory rules'
当 QQmlPropertyList 被设置为使用
在 C++ 中定义的 QML 组件的一部分时,我发现很难确认插入到 QQmlPropertyList 中的项目的 object 所有权规则
Q_CLASSINFO("DefaultProperty", "values")
DTech 在 QQmlListProperty - writable QList violates QML's memory management rules? 中问了类似的问题,但他担心删除 QML 中定义的组件的后果。我比较担心一般插入到列表中的object的生命周期要求。
现在据我了解:
如果 children 是从 QML 创建和插入的,它们的 parent 将
自动设置并且 objects 由 QmlEngine 管理。 (parent 应该已经在追加时定义)
如果我从 C++ 端插入一些东西,我需要管理
一辈子自己。 (parent 将在追加时为 nullptr)
针对“违反 QML 的内存管理规则”发出警告的 QT 文档。在 http://doc.qt.io/qt-5/qqmllistproperty.html 中,但我找不到任何以清晰、简洁的方式实际说明这些内容的内容。
目前我已经实现了一个非常类似于向量的包装器
http://doc.qt.io/qt-5/qtqml-referenceexamples-properties-example.html
但是我添加了两条规则:
- 追加检查以查看正在添加的 object 是否具有 nullptr parent,如果有则取得所有权。
- 如果当前列表 parent 拥有任何 object,则清除 object,在 object 上执行 'deleteLater' 并将其 parent 设置为 nullptr
我假设因为我们在添加 objects 和 nullptr parents 时设置了 parent,QT 将删除 QObjects 在 parent 超出范围时自动拥有。
是否还有更多规则是我遗漏并需要注意的?
我的实现代码以防万一以上需要澄清:
template <typename T>
class QmlListFacade {
private:
std::vector<T *> _storage;
static void append(QQmlListProperty<T> *list, T *newValue) {
// take ownership of the object if none are currently defined
auto obj = static_cast<QObject *>(newValue);
if( obj->parent() == nullptr) {
obj->setParent(list->object);
}
auto internalList = reinterpret_cast<QmlListFacade *>(list->data);
internalList->_storage.push_back(newValue);
}
static int count(QQmlListProperty<T> *list) {
return reinterpret_cast<QmlListFacade *>(list->data)->_storage.size();
}
static T *get(QQmlListProperty<T> *list, int index) {
return reinterpret_cast<QmlListFacade *>(list->data)->_storage[index];
}
static void clear(QQmlListProperty<T> *list) {
auto internalList = reinterpret_cast<QmlListFacade *>(list->data);
for( auto item :internalList->_storage){
// only delete if we are the owners.
auto obj = static_cast<QObject *>(item);
if( obj->parent() == list->object){
obj->setParent(nullptr);
obj->deleteLater();
}
}
return internalList->_storage.clear();
}
public:
QmlListFacade() = default;
QQmlListProperty<T> values(QObject *parent) {
return QQmlListProperty<T>(parent, this, &QmlListFacade::append, &QmlListFacade::count, &QmlListFacade::get,
&QmlListFacade::clear);
}
};
从发现 QML 不确定的对象生命周期管理并为此奋斗了将近 3 年的人的角度来看,在 window 的经验中,我没有遇到任何声明定义的对象树被错误处理的情况.
问题出在动态创建的对象上,无论它们是否有父对象,或者代码中存在多少对它们的活动引用,它们往往偶尔会被删除。如果你想确保那些不被删除,给他们明确的 CPP 所有权。
这将防止引擎在仍在使用时销毁这些对象。当对象的父对象被销毁时,对象仍将被收集,就像在 C++ 中发生的那样 API.
请注意,此警告仅出现在接受 QList
的构造函数中,而不出现在接受控制函数指针的构造函数中。因此,如果有的话,您至少可以从不使用该格式的事实中找到安慰。我对两者都进行了大量测试,但没有遇到任何功能差异。该警告可能放错了地方,措辞不当,甚至完全没有意义,而且没有提供任何有关其含义及其可能含义的上下文。只是在测试中进行彻底的测试以在他们的婴儿期发现任何问题。
当 QQmlPropertyList 被设置为使用
在 C++ 中定义的 QML 组件的一部分时,我发现很难确认插入到 QQmlPropertyList 中的项目的 object 所有权规则Q_CLASSINFO("DefaultProperty", "values")
DTech 在 QQmlListProperty - writable QList violates QML's memory management rules? 中问了类似的问题,但他担心删除 QML 中定义的组件的后果。我比较担心一般插入到列表中的object的生命周期要求。
现在据我了解:
如果 children 是从 QML 创建和插入的,它们的 parent 将 自动设置并且 objects 由 QmlEngine 管理。 (parent 应该已经在追加时定义)
如果我从 C++ 端插入一些东西,我需要管理 一辈子自己。 (parent 将在追加时为 nullptr)
针对“违反 QML 的内存管理规则”发出警告的 QT 文档。在 http://doc.qt.io/qt-5/qqmllistproperty.html 中,但我找不到任何以清晰、简洁的方式实际说明这些内容的内容。
目前我已经实现了一个非常类似于向量的包装器 http://doc.qt.io/qt-5/qtqml-referenceexamples-properties-example.html
但是我添加了两条规则:
- 追加检查以查看正在添加的 object 是否具有 nullptr parent,如果有则取得所有权。
- 如果当前列表 parent 拥有任何 object,则清除 object,在 object 上执行 'deleteLater' 并将其 parent 设置为 nullptr
我假设因为我们在添加 objects 和 nullptr parents 时设置了 parent,QT 将删除 QObjects 在 parent 超出范围时自动拥有。
是否还有更多规则是我遗漏并需要注意的?
我的实现代码以防万一以上需要澄清:
template <typename T>
class QmlListFacade {
private:
std::vector<T *> _storage;
static void append(QQmlListProperty<T> *list, T *newValue) {
// take ownership of the object if none are currently defined
auto obj = static_cast<QObject *>(newValue);
if( obj->parent() == nullptr) {
obj->setParent(list->object);
}
auto internalList = reinterpret_cast<QmlListFacade *>(list->data);
internalList->_storage.push_back(newValue);
}
static int count(QQmlListProperty<T> *list) {
return reinterpret_cast<QmlListFacade *>(list->data)->_storage.size();
}
static T *get(QQmlListProperty<T> *list, int index) {
return reinterpret_cast<QmlListFacade *>(list->data)->_storage[index];
}
static void clear(QQmlListProperty<T> *list) {
auto internalList = reinterpret_cast<QmlListFacade *>(list->data);
for( auto item :internalList->_storage){
// only delete if we are the owners.
auto obj = static_cast<QObject *>(item);
if( obj->parent() == list->object){
obj->setParent(nullptr);
obj->deleteLater();
}
}
return internalList->_storage.clear();
}
public:
QmlListFacade() = default;
QQmlListProperty<T> values(QObject *parent) {
return QQmlListProperty<T>(parent, this, &QmlListFacade::append, &QmlListFacade::count, &QmlListFacade::get,
&QmlListFacade::clear);
}
};
从发现 QML 不确定的对象生命周期管理并为此奋斗了将近 3 年的人的角度来看,在 window 的经验中,我没有遇到任何声明定义的对象树被错误处理的情况.
问题出在动态创建的对象上,无论它们是否有父对象,或者代码中存在多少对它们的活动引用,它们往往偶尔会被删除。如果你想确保那些不被删除,给他们明确的 CPP 所有权。
这将防止引擎在仍在使用时销毁这些对象。当对象的父对象被销毁时,对象仍将被收集,就像在 C++ 中发生的那样 API.
请注意,此警告仅出现在接受 QList
的构造函数中,而不出现在接受控制函数指针的构造函数中。因此,如果有的话,您至少可以从不使用该格式的事实中找到安慰。我对两者都进行了大量测试,但没有遇到任何功能差异。该警告可能放错了地方,措辞不当,甚至完全没有意义,而且没有提供任何有关其含义及其可能含义的上下文。只是在测试中进行彻底的测试以在他们的婴儿期发现任何问题。