2015-01-16 170 views
2

我试图测试QML以了解它如何与C++一起工作。我有ClassAClassB - 2个类似的C++类。这是一个ClassA。所有的方法都是用自己的名字来解释,所以我不会在这里放置实现。QML内存管理

class ClassB; 
class ClassA : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit ClassA(QObject *parent = 0); 
    ~ClassA(); 
    Q_PROPERTY(ClassB* classB READ getClassB WRITE setClassB NOTIFY classBChanged) 
    ClassB* getClassB() const; 
    void setClassB(ClassB *classB); 
signals: 
    void classBChanged(); 
private: 
    ClassB *m_classB; 
}; 

ClassB是一样的,只是改变所有*lassA**lassB*和所有*lassB**lassA*

然后我注册在QML都归类与

qmlRegisterType<ClassA>("testmodule.test",1,0,"ClassA"); 
qmlRegisterType<ClassB>("testmodule.test",1,0,"ClassB"); 

并在鼠标QML代码单击创建两个对象是这样的:

onClicked: { 
    var comp = Qt.createComponent("TClassA.qml"); //TClassA.qml is 
                //a component of type 
                //ClassA 
    var ca = comp.createObject(); 
    comp = Qt.createComponent("TClassB.qml"); 
    var cb = comp.createObject(); 
    ca.classB = cb; 
    cb.classA = ca; 
    parent.blockFromGC = ca; 
} 

此后,我称之为垃圾收集与gc()。我预计ca被阻止从parent.blockFromGC删除和cb被阻止从ca删除参考。但垃圾收集器销毁cb,之后parent.blockFromGC.classB === null

所以我有第二MouseArea与此代码:

onClicked: { 
    console.log(mouse.button) 
// if (mouse.button == Qt.RightButton) { 
//  console.log(parent.vasya.classB) 
// } 
    gc(); 
    console.log(parent.blockFromGC.classB) //I use cb here 
} 

所以,当我点击MouseArea我在控制台中看到:

qml: 1 //Left button 
qml: null //value of parent.blockFromGC.classB 
classB destroyed: TQMLClassB(0x34960d0) //I have qDebug() in destructor 

所以我的目标cb被摧毁。

所以我有这样的问题:

1)是否有一种方法,我怎么能注册一个C++型为基本型,这样我就可以 写var ca = new ClassA()而不是创建一个*.qml文件,创建一个组件,并最终创造一个东西?

2)为什么垃圾收集器破坏了我的cb对象,我应该怎么做 以防止删除此对象?

此外!如果我取消注释那些注释行

// if (mouse.button == Qt.RightButton) { 
//  console.log(parent.vasya.classB) 
// } 

无论按下哪个按钮,对象都不会被销毁。

qml: 1 //left button 
qml: TQMLClassB(0x3df8e90) //object is alive 
..... 
qml: 2 //right button 
qml: TQMLClassB(0x3df8e90) //before gc() - alive 
qml: TQMLClassB(0x3df8e90) //after gc() - alive 

3)在哪里可以阅读关于QML内存管理的详细资料?我觉得这种行为真的很奇怪..

加法1:我玩这种情况多一点,结果是不可预知的。我从5.3更新到Qt 5.4,这种删除对象的行为已经消失。问题在于行为如此不可预测,以至于我无法在Qt 5.4中重现这种行为,并不意味着问题得到解决。我会尝试查看错误报告和错误修复。如果我找到了什么,我会在这里发布。如果没有,我会尝试在Qt 5.4中重现这种情况并发布报告。

+0

你可以把'ClassA'放入一个'Component'中,然后通过'var ca = thisComponent.createObject(parent)'创建它。至于对象破坏 - 你能确定在哪个步骤调用了desctructor?正如我所知道的,如果没有引用它,那么你就不得不以这种方式寻找对象。 – folibis

+0

@folibis在调试模式下,这个问题成为一个概率问题。有时它发生了,有时并没有发生。跟踪没有给我太多的信息。如预期的那样,所有函数调用都在共享库中完成,其中一些已隐藏。而且它们都具有通常的名称,用于试图删除和反对的功能。无论如何,读一个补充发布,并感谢您的建议如何不需要创建* .qml文件。 – JustAnotherCurious

回答

2
  1. 像任何QML类型,你可以在另一静态定义组件:

    Component { 
        id: classAComponent 
        ClassA { } 
    } 
    onClicked { 
        var ca = classAComponent.createObject() 
    } 
    
  2. 这里有一个细微之处:分配QML对象到QML property将增加它的JavaScript REF-数。但是在C++对象的Q_PROPERTY中只存储的实例只有不会被垃圾收集器标记。

    QML拥有双重所有权系统。首先它定义了用于显示和所有权的QObject/QQuickItem的层次结构。附加在这个骨干上的是一个垃圾收集系统,任何QML对象都可以通过property var拥有一个JavaScript对象树。所以为了保持你的ClassB对象有​​效,你必须保存在QML属性中,或者在调用component.createObject()时为它提供一个父对象(它是一个拥有者;它会被销毁的任何JS参照它当父被破坏)

    实施例与QML属性:

    Component { 
        id: classAComponent 
        ClassA { 
         property Item refClassB 
        } 
    } 
    onClicked { 
        var ca = classAComponent.createObject() 
        ca.refClassB = classBComponent.createObject() 
    } 
    

    理想的情况下,你应该动态地避免创建对象尽可能和使用C++对象静态像正常QML部件并让陈述性结构保持Q自动物体骨干,像这样:

    ClassA { 
        classB: ClassB { } 
    } 
    
  3. 可悲的是没有这么多,我知道的最好的,更多的QML比C++是Dynamic QML Object Creation from JavaScript

+0

1)谢谢。这种方式比我更好。 2)我另外写道,在Qt的新版本中,这种情况并不像我描述的那样。在调试中,它在prev中是随机的。版。而且,如果有人创建了一个对象,他不应该关心如何描述组件(QML或QObject)。我希望这是一个错误,现在它已经修复并希望“但是只存储在C++对象的Q_PROPERTY中的实例不会被垃圾收集器标记”现在不成立。 =) – JustAnotherCurious