? ? ? 在Qt中,顯式使用new創建的對象通常不需要顯式調用delete來釋放內存,這是因為Qt提供了一種基于對象樹(Object Tree)和父子關系(Parent-Child Relationship)的內存管理機制。這種機制可以自動管理對象的生命周期,確保在適當的時候釋放內存:
? ? ? 在Qt中,每個QObject或其派生類(如QWidget、QPushButton)都可以有一個父對象(Parent)。
? ? ? 當創建一個對象時,如果指定了父對象,則該對象會被添加到父對象的子對象列表中。
? ? ? 當父對象被銷毀時,Qt會自動遞歸銷毀其所有子對象,從而釋放內存。
? ? ? QObject的析構函數會遍歷其子對象列表,并遞歸調用每個子對象的析構函數。這種機制確保了所有子對象都會被正確釋放。
? ? ? 顯式調用delete僅在對象沒有父對象或需要手動管理生命周期時才需要。
? ? ? 對象樹:
? ? ? (1).QObject在對象樹中自我組織(QObjects organize themselves in object trees)。當你創建一個以另一個對象為父對象的QObject時,它會被添加到父對象的 children()列表中,并在父對象被刪除時被刪除。事實證明,這種方法非常適合GUI對象的需求。例如,QShortcut(鍵盤快捷鍵)是相關窗口的子對象,因此當用戶關閉該窗口時,快捷方式也會被刪除。
? ? ? (2).QWidget是Qt Widgets模塊的基類,它擴展了父子關系(parent-child relationship)。QWidget繼承自QObject、QPaintDevice。
? ? ? (3).你還可以自行刪除子對象,這些子對象會從其父對象中移除。
? ? ? (4).每個QObject都可以參與對象樹。每個QObject都有一個子對象列表,也可能有一個父QObject。當QObject被銷毀時,其所有附加子對象都會隨之銷毀。
? ? ? 對象樹(Object Tree)是由父對象(Parent Object)及其子對象(Child Objects)構成的樹狀結構。在這個結構中,每一個對象都可以擁有子對象,而每個子對象又只能有一個父對象。這種父子關系不僅反映了對象之間的層級結構,還意味著當父對象被銷毀時,所有的子對象也將被自動銷毀。
? ? ? QObject構造/析構順序:當QObject在堆(heap)上創建時(即使用new創建),可以按任意順序從它們構建樹,之后,可以按任意順序銷毀樹中的對象。當刪除樹中的任何QObject時,如果該對象有父對象,則析構函數會自動從其父對象中刪除該對象。如果該對象有子對象,則析構函數會自動刪除每個子對象。無論析構順序如何,都不會刪除兩次QObject。
? ? ? QObject包含許多用于檢查此對象樹的方法:
? ? ? (1).parent():獲取對象的父對象,或為null。
? ? ? (2).setParent():設置對象的父對象。
? ? ? (3).children():獲取屬于該對象的子對象列表。
? ? ? 在Qt框架中,幾乎所有的事物都是對象。對象通常使用動態內存分配(Dynamic Memory Allocation)創建,即通過new關鍵字。在Qt中,當一個對象被創建時,可以指定另一個對象作為它的父對象。這種關系建立后,子對象的生命周期便與父對象緊密相關。當父對象被銷毀時,它會自動銷毀其所有子對象,從而保證資源的正確釋放。
? ? ? C++中的繼承主要用于代碼復用和多態性,而Qt中的父子關系主要用于內存管理和對象生命周期的控制。
? ? ? 下載Qt6.8源碼:
git clone git://code.qt.io/qt/qt5.git
cd qt5
git submodule update --init --recursive
git checkout v6.8.0
? ? ? 以下為測試代碼:
#include <QObject>
#include <QDebug>namespace {class MyObject : public QObject {
public:explicit MyObject(const QString& name, QObject* parent = nullptr) : QObject(parent), name_(name){qDebug() << "Constructor: " << name_;}~MyObject(){qDebug() << "Destructor: " << name_;}QString name() const{return name_;}private:QString name_{};
};} // namespaceint test_memory_management()
{MyObject* parent = new MyObject("parent object");MyObject* child1 = new MyObject("child object1", parent);//MyObject* child2 = new MyObject("child object2", parent);MyObject* child2 = new MyObject("child object2");child2->setParent(parent);for (auto obj : parent->children()) {qDebug() << "child object name: " << ((MyObject*)obj)->name();}qDebug() << "child2 parent object name: " << ((MyObject*)child2->parent())->name();delete parent; // manually delete the parent objectreturn 0;
}
? ? ? 執行結果如下圖所示:
? ? ? GitHub:https://github.com/fengbingchun/Qt_Test