我发现很难确认插入到 QQmlPropertyList 中的项目的对象所有权规则,当它被设置为 C++ 中定义的 QML 组件的一部分时
Q_CLASSINFO("DefaultProperty", "values")
DTech 在:QQmlListProperty - 可写 QList 违反 QML 的内存管理规则?,但他担心删除 QML 中定义的组件的后果。我更担心一般插入到列表中的对象的生命周期要求。
现在据我了解:
如果孩子是从 QML 创建和插入的,他们的父母将被自动设置,并且对象由 QmlEngine 管理。(父级应该已经在附加上定义)
如果我从 C++ 端插入一些东西,我需要自己管理生命周期。(父级在追加时为 nullptr)
QT 文档警告不要“违反 QML 的内存管理规则”。在 http://doc.qt.io/qt-5/qqmllistproperty.html但我找不到任何以清晰、简洁的方式实际说明这些内容的内容。
目前我已经实现了一个非常类似于 http://doc.qt.io/qt-5/qtqml-referenceexamples-properties-example.html的向量的包装器
但是我添加了两条规则:
- 附加检查以查看要添加的对象是否具有nullptr 父级,如果有,则获取所有权。
- 清除当前列表父对象是否拥有任何对象时,对对象执行“deleteLater”并将其父对象设置为nullptr
我假设因为我们在添加具有nullptr父对象的对象时设置了父对象,所以当父对象超出范围时,QT 将自动删除拥有的QObjects 。
是否还有更多我遗漏并需要注意的 规则?
我的实现代码以防万一以上需要一些澄清:
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);
}
};