0

我发现很难确认插入到 QQmlPropertyList 中的项目的对象所有权规则,当它被设置为 C++ 中定义的 QML 组件的一部分时

Q_CLASSINFO("DefaultProperty", "values")

DTech 在:QQmlListProperty - 可写 QList 违反 QML 的内存管理规则?,但他担心删除 QML 中定义的组件的后果。我更担心一般插入到列表中的对象的生命周期要求。

现在据我了解:

  1. 如果孩子是从 QML 创建和插入的,他们的父母将被自动设置,并且对象由 QmlEngine 管理。(父级应该已经在附加上定义)

  2. 如果我从 C++ 端插入一些东西,我需要自己管理生命周期。(父级在追加时为 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);
  }

};

4

1 回答 1

0

从发现 QML 不确定的对象生命周期管理并为此苦苦挣扎近 3 年的人的角度来看,在那个经验窗口中,我没有遇到任何声明性定义的对象树被错误处理的情况。

问题在于动态创建的对象,无论它们是否有父对象,或者代码中存在多少对它们的活动引用,这些对象往往会偶尔被删除。如果您想确保那些不会被删除,请给他们明确的 CPP 所有权。

这将防止引擎在仍在使用时破坏这些对象。当它们的父对象被销毁时,对象仍将被收集,就像在 C++ API 中发生的那样。

请注意,此警告仅出现在接受 a 的构造函数中,QList而不是接受控制函数指针的构造函数中。因此,如果有的话,您至少可以在您没有使用该格式的事实中找到安慰。我已经对两者进行了大量测试,但没有遇到任何功能差异。除了没有提供任何关于它的含义和可能的含义的上下文之外,该警告可能放错地方、措辞不当甚至完全没有意义。只需彻底测试以发现婴儿期的任何问题。

于 2018-06-07T11:41:51.233 回答