iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0
Software Development

Qt 6 跨平台應用程式開發系列 第 11

D11: Qt 物件生命週期淺析

  • 分享至 

  • xImage
  •  

我們已經連續四天介紹了多種不同的圖形元件,包括按鈕、文字標籤、下拉選單、文字輸入框、拉桿、數字框等等。不知道你有沒有發現一件有點怪怪的事(熟練的C++程式設計師應該已經敏銳的察覺到了)

那就是:我們的範例程式,怎麼都只有用 new 創建新物件,卻一次都沒有用 delete 消滅物件呢?

這樣,不會造成記憶體洩漏(memory leak)嗎?

簡短的答案是:不會有記憶體洩漏喔!

為什麼不會呢?這就要談到 Qt 物件的親子關係和生命週期啦,且聽我慢慢道來。

QObject 間的親子關係

所有的 Qt 視窗元件,比如 QLabel/QPushButton 等等,只要我們追溯他們的繼承體系,最終就會發現他們全部都繼承自 QObject 這個最頂層的根物件。

而 QObject 最重要的設計,就是親子關係。

當你創建一個 QObject 時,可以給目前物件指定一個爸爸。由爸爸物件來負責管理目前物件的生命週期。

怎麼指定爸爸呢?可以透過建構子:

QObject* dad = new QObject;
QObject* kid = new QObject(dad); // 用建構子

或者 setParent() 方法:

QObject* dad = new QObject;
QObject* kid = new QObject;
kid->setParent(dad); // 用setParent()方法

或者建構圖形元件的樹狀結構,也會順便設定爸爸

QWidget* dad = new QWidget;
dad->setLayout(new QVBoxLayout);

QLabel* kidLabel = new QLabel("文字標籤");
QLineEdit* kidLineEdit = new QLineEdit;

dad->layout()->addWidget(kidLabel);    // 文字標籤的爸爸是 QWidget* dad
dad->layout()->addWidget(kidLineEdit); // 文字輸入框的爸爸也是 QWidget* dad

爸爸物件也可以指定它自己的爸爸物件(變成爺爺物件了),最終組織成一個巨大的物件樹。但是別忘了,每個 QObject 物件只會有一個爸爸,如果一個物件改跟了另外一個爸爸 (透過setParent() 或者圖形排版變化),那該物件就屬於新爸爸管理囉。

QObject 的連鎖釋放

當親子階層關係建立之後,爸爸物件就會負責管理孩子物件的生命週期。

簡單講:當我們釋放爸爸物件時,爸爸元件就會「連帶釋放他所有的孩子物件」。

所以當你回頭去看我們前幾天的範例程式,在 main() 方法的尾聲,一旦爸爸元件 QWidget w 消滅,他底下的所有孩子元件也都會一起消滅,並且歸還記憶體給作業系統,這就是為什麼不會發生記憶體洩漏的原因囉。

Qt 的這個設計相當聰明,雖然在生命週期管理方面,沒有採用引用記數的 std::shared_ptr 那麼有彈性。但是親子關係的設定,會強迫程式設計師為 QObject 組織一個嚴謹樹狀結構,更簡單而且更不容易寫出 BUG。


上一篇
D10: 常用元件介紹 QComboBox
下一篇
D12: 一步一步做出看圖軟體
系列文
Qt 6 跨平台應用程式開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言