2015-01-16 5 views
2

Я пытаюсь проверить QML, чтобы понять, как это работает с C++. У меня есть ClassA и ClassB - 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' внутри' Компонента' и создать ее через 'var ca = thisComponent.createObject (parent)'. Что касается уничтожения объектов - можете ли вы убедиться, на каком этапе был вызван дескриптор? Как я знаю, объект может быть разрушен, если нет ссылок на него, поэтому вам нужно искать таким образом. – folibis

+0

@folibis В режиме отладки эта проблема стала проблемой вероятности. Иногда это случалось, а иногда и нет. След не дал мне много информации. Все вызовы функций выполнялись, как и ожидалось, в общих библиотеках, а некоторые из них были скрыты. И все они имеют довольно обычные имена для функций, которые пытаются удалить и объект. В любом случае, прочитайте дополнение к сообщению и спасибо за советы, как это можно сделать без создания файла * .qml. – JustAnotherCurious

ответ

2
  1. Как и любой тип QML, вы можете определить компонент статически в другой:

    Component { 
        id: classAComponent 
        ClassA { } 
    } 
    onClicked { 
        var ca = classAComponent.createObject() 
    } 
    
  2. Существует тонкость здесь: назначение объекта QML к QML property увеличит JavaScript реф-кол , Но экземпляр, сохраненный в , только в Q_PROPERTY объекта C++ не будет помечен сборщиком мусора.

    QML имеет систему двойного владения. Сначала он определяет иерархию QObject/QQuickItem, используемую для отображения и владения. К этому хребту прилагается система сбора мусора, где любой объект QML может владеть деревом объекта JavaScript через property var.

    Так держать ваши ClassB объект живы, вы должны либо держать его в QML собственности, или как обеспечить родитель для этого при вызове component.createObject() (это тяжелая собственность, она будет уничтожено независимо любой JS ссылки на него, когда родитель будет уничтожен)

    Пример со свойством QML:

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

    в идеале вы должны избегать динамического создания объекта как можно больше и использования C++ объекты статически, как обычные компоненты QML и пусть декларативная структура поддерживает QObje кт позвоночника автоматически, как это:

    ClassA { 
        classB: ClassB { } 
    } 
    
  3. К сожалению, не так много, лучшее, что я знаю, больше для QML, чем C++ является Dynamic QML Object Creation from JavaScript.

+0

1) Спасибо. Этот способ намного приятнее, чем я. 2) Я писал в дополнении, что в новой версии Qt эта ситуация не ведет себя так, как я описал. И под отладкой он был случайным в превью. версия. Более того, если кто-то создает объект, ему все равно, как описывается компонент (QML или QObject). Я надеюсь, что это была ошибка, и теперь она исправлена ​​и надеется «Но экземпляр, хранящийся только в Q_PROPERTY объекта C++, не будет отмечен сборщиком мусора», теперь не соответствует действительности. знак равно – JustAnotherCurious

Смежные вопросы