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的生命周期要求。

现在据我了解:

  1. 如果 children 是从 QML 创建和插入的,它们的 parent 将 自动设置并且 objects 由 QmlEngine 管理。 (parent 应该已经在追加时定义)

  2. 如果我从 C++ 端插入一些东西,我需要管理 一辈子自己。 (parent 将在追加时为 nullptr)

针对“违反 QML 的内存管理规则”发出警告的 QT 文档。在 http://doc.qt.io/qt-5/qqmllistproperty.html 中,但我找不到任何以清晰、简洁的方式实际说明这些内容的内容。

目前我已经实现了一个非常类似于向量的包装器 http://doc.qt.io/qt-5/qtqml-referenceexamples-properties-example.html

但是我添加了两条规则:

  1. 追加检查以查看正在添加的 object 是否具有 nullptr parent,如果有则取得所有权。
  2. 如果当前列表 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 的构造函数中,而不出现在接受控制函数指针的构造函数中。因此,如果有的话,您至少可以从不使用该格式的事实中找到安慰。我对两者都进行了大量测试,但没有遇到任何功能差异。该警告可能放错了地方,措辞不当,甚至完全没有意义,而且没有提供任何有关其含义及其可能含义的上下文。只是在测试中进行彻底的测试以在他们的婴儿期发现任何问题。