Управление памятью в Qt?
Я довольно новичок в Qt и задаюсь вопросом о некоторых базовых вещах, связанных с управлением памятью и жизнью объектов. Когда мне нужно удалять и / или уничтожать мои объекты? Все это обрабатывается автоматически?
В приведенном ниже примере, какие объекты, которые я создаю, мне нужно удалить? Что происходит с переменной экземпляра myOtherClass
когда myClass
разрушен? Что произойдет, если я вообще не удаляю (или уничтожаю) свои объекты? Будет ли это проблемой для памяти?
MyClass.h
class MyClass
{
public:
MyClass();
~MyClass();
MyOtherClass *myOtherClass;
};
MyClass.cpp
MyClass::MyClass() {
myOtherClass = new MyOtherClass();
MyOtherClass myOtherClass2;
QString myString = "Hello";
}
Как вы можете видеть, это довольно просто для новичка, но где я могу узнать об этом простым способом?
4 ответа
Если вы строите свою собственную иерархию с QObject
s, то есть вы инициализируете все вновь созданные QObject
с родителем,
QObject* parent = new QObject();
QObject* child = new QObject(parent);
тогда достаточно delete
parent
, поскольку parent
деструктор позаботится об уничтожении child
, (Это делается путем выдачи сигналов, так что это безопасно, даже когда вы удаляете child
вручную перед родителем.)
Вы также можете сначала удалить ребенка, порядок не имеет значения. Для примера, где порядок имеет значение, вот документация о деревьях объектов.
Если твой MyClass
не дитя QObject
вам придется использовать простой C++ способ делать вещи.
Также обратите внимание, что родительско-дочерняя иерархия QObject
Обычно s не зависит от иерархии иерархии классов C++ / дерева наследования. Это означает, что назначенный ребенок не должен быть прямым подклассом своего родителя. Любой (подкласс) QObject
будет достаточно.
Однако могут существовать некоторые ограничения, налагаемые конструкторами по другим причинам; такой как в QWidget(QWidget* parent=0)
где родитель должен быть другим QWidget
из-за, например, флагов видимости и потому, что вы бы сделали базовый макет таким образом; но для системы иерархии Qt в целом вам разрешено иметь QObject
как родитель.
Я хотел бы расширить ответ Дебильски, указав, что концепция владения очень важна в Qt. Когда класс A предполагает владение классом B, класс B удаляется, когда класс A удаляется. Существует несколько ситуаций, когда один объект становится владельцем другого, а не только при создании объекта и указании его родителя.
Например:
QVBoxLayout* layout = new QVBoxLayout;
QPushButton someButton = new QPushButton; // No owner specified.
layout->addWidget(someButton); // someButton still has no owner.
QWidget* widget = new QWidget;
widget->setLayout(layout); // someButton is "re-parented".
// widget now owns someButton.
Другой пример:
QMainWindow* window = new QMainWindow;
QWidget* widget = new QWidget; //widget has no owner
window->setCentralWidget(widget); //widget is now owned by window.
Поэтому часто проверяйте документацию, в ней обычно указывается, повлияет ли метод на владение объектом.
Как утверждает Дебилски, эти правила применяются ТОЛЬКО к объектам, производным от QObject. Если ваш класс не является производным от QObject, вам придется справиться с уничтожением самостоятельно.
Родитель (либо объект QObject, либо его производный класс) имеет список указателей на его дочерние элементы (QObject/ его производный). Родитель удалит все объекты в своем дочернем списке, пока родитель уничтожен. Вы можете использовать это свойство QObject для автоматического удаления дочерних объектов при каждом удалении родительского объекта. Связь может быть установлена с использованием следующего кода
QObject* parent = new QObject();
QObject* child = new QObject(parent);
delete parent;//all the child objects will get deleted when parent is deleted, child object which are deleted before the parent object is removed from the parent's child list so those destructor will not get called once again.
Есть другой способ управлять памятью в Qt, используя smartpointer. Следующая статья описывает различные умные указатели в Qt. https://blog.qt.digia.com/blog/2009/08/25/count-with-me-how-many-smart-pointer-classes-does-qt-have/
Чтобы добавить к этим ответам, для проверки, я бы порекомендовал вам использовать Visual Leak Detetor
библиотека для ваших проектов Visual C++, включая проекты Qt, поскольку она основана на C++, эта библиотека совместима с new, delete, free and malloc
Заявления, это хорошо документированы и просты в использовании. Не забывайте, что когда вы создаете свой собственный QDialog
или же QWidget
унаследованный интерфейсный класс, а затем создайте новый объект этого класса, не забудьте выполнить setAttribute(Qt::WA_DeleteOnClose)
функция вашего объекта.