QML QQmlPropertyList - время жизни объекта и «правила памяти» - PullRequest
0 голосов
/ 07 июня 2018

Мне трудно подтвердить правила владения объектом для элементов, вставленных в QQmlPropertyList, когда он настроен как часть компонента QML, определенного в C ++ с помощью

Q_CLASSINFO("DefaultProperty", "values")

DTech спросил что-то похожее в: QQmlListProperty - доступный для записи QList нарушает правила управления памятью QML? , но его беспокоили последствия удаления компонентов, определенных в QML.Меня больше беспокоит требования к жизненному циклу объектов, включенных в список в целом.

Теперь из того, что я понимаю:

  1. Если дочерние элементы создаются и вставляются из QML, их родители автоматически устанавливаются, а объекты управляются QmlEngine.(родитель должен быть уже определен при добавлении)

  2. Если я вставлю что-то со стороны C ++, мне нужно самому управлять временем жизни.(parent будет nullptr при добавлении)

Документы QT для предупреждения о «нарушении правил управления памятью в QML».в http://doc.qt.io/qt-5/qqmllistproperty.html но я не могу найти ничего, что на самом деле излагало бы это ясно и кратко.

В настоящее время я реализовал обертку вокруг вектора, очень похожего на http://doc.qt.io/qt-5/qtqml-referenceexamples-properties-example.html

Однако я добавил два правила:

  1. Добавление проверок, чтобы увидеть, является ли объект объектомдобавленный имеет nullptr родитель и, если так, становится владельцем.
  2. При очистке, если какой-либо объект принадлежит текущему родительскому списку, выполняет для него '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);
  }

};

1 Ответ

0 голосов
/ 07 июня 2018

С точки зрения того, кто обнаружил сомнительное управление временем жизни объектов QML и боролся с этим уже почти 3 года, в этом окне опыта я не сталкивался ни с одним случаем декларативно определенного дерева объектов, с которым неправильно обращались.

Проблемы связаны с объектами, которые создаются динамически, они, как правило, иногда удаляются независимо от того, есть ли у них родительский элемент или сколько активных ссылок на них существует в коде.Если вы хотите, чтобы они не удалялись, дайте им явное право собственности на CPP.

Это предотвратит уничтожение движком этих объектов, пока они еще используются.Объекты по-прежнему будут собираться после уничтожения их родителей, как это происходит в C ++ API.

Обратите внимание, что это предупреждение присутствует только в конструкторе, который принимает QList, а не в том, который принимаетуказатели на функции управления.Так что, если что-нибудь, вы можете по крайней мере найти утешение в том факте, что вы не используете этот формат.Я сделал много испытаний на обоих и не встретил никаких функциональных отличий.Это предупреждение могло быть неуместным, плохо сформулированным и даже совершенно бессмысленным в дополнение к тому, что оно не содержало контекста того, что оно означает и каковы могут быть его последствия.Просто будьте внимательны при тестировании, чтобы выявить проблемы в младенчестве.

...