代码之家  ›  专栏  ›  技术社区  ›  Andrew Goedhart

qml qqmlpropertylist-包含的对象生存期和“内存规则”

  •  0
  • Andrew Goedhart  · 技术社区  · 6 年前

    我发现,当将其设置为C++中定义的QML组件的一部分时,很难确认插入到QQMLPurryType列表中的项的对象所有权规则。

    Q_CLASSINFO("DefaultProperty", "values")
    

    dtech问了类似的问题: QQmlListProperty - writable QList violates QML's memory management rules? ,但他担心删除qml中定义的组件的后果。我更担心的是插入到列表中的对象的生命周期需求。

    据我所知:

    1. 如果子项是从qml创建和插入的,则其父项将 被自动设置,对象由qmlengine管理。(父项应已在追加时定义)

    2. 如果我从C++方面插入一些东西,我需要管理 我的一生。(追加时父级为空ptr)

    qt文档用于警告“违反qml的内存管理规则”。 http://doc.qt.io/qt-5/qqmllistproperty.html 但我找不到任何东西能清楚、简洁地表达这些。

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

    不过,我增加了两条规则:

    1. 附加检查以查看要添加的对象是否具有 努尔普特 父母,如果是的话,拥有所有权。
    2. 如果任何对象属于当前列表父对象,则在清除时对该对象执行“deleteLater”,并将其父对象设置为 努尔普特

    我假设这是因为我们在添加对象时设置了父对象 努尔普特 父级,qt将删除 QObjts 当父级超出范围时自动拥有。

    还有别的吗 规则 我失踪了需要注意的?

    我的实现代码,以防上面需要澄清:

    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 回复  |  直到 6 年前
        1
  •  0
  •   dtech    6 年前

    从发现qml的对象生命周期管理的人的角度来看,在这段经历中,我没有遇到任何声明性定义的对象树被错误处理的情况。

    问题在于动态创建的对象,这些对象有时会被删除,而不管它们是否有父对象,或者代码中存在多少对它们的活动引用。如果您想确保这些文件不会被删除,请明确赋予它们cpp所有权。

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

    注意,此警告仅在接受 QList 而不是接受控制函数指针的那个。所以,如果有什么不同的话,你至少可以从没有使用这种格式中找到安慰。我已经对两者做了大量的测试,但没有遇到任何功能上的差异。这一警告可能放错地方,措词不当,甚至完全没有意义,除了没有提供它的含义和可能的含义的任何上下文之外。只要仔细检查,发现婴儿期的任何问题就行了。