Мне трудно подтвердить правила владения объектом для элементов, вставленных в QQmlPropertyList, когда он настроен как часть компонента QML, определенного в C ++ с помощью
Q_CLASSINFO("DefaultProperty", "values")
DTech спросил что-то похожее в: QQmlListProperty - доступный для записи QList нарушает правила управления памятью QML? , но его беспокоили последствия удаления компонентов, определенных в QML.Меня больше беспокоит требования к жизненному циклу объектов, включенных в список в целом.
Теперь из того, что я понимаю:
Если дочерние элементы создаются и вставляются из QML, их родители автоматически устанавливаются, а объекты управляются QmlEngine.(родитель должен быть уже определен при добавлении)
Если я вставлю что-то со стороны C ++, мне нужно самому управлять временем жизни.(parent будет 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);
}
};