Qt 智能指針的具體使用
QScopedPointer
QScopedPointer 是 Qt 提供的一個(gè)智能指針,主要用于簡(jiǎn)化資源管理,防止內(nèi)存泄漏和懸掛指針問(wèn)題。它屬于 Qt 的內(nèi)存管理工具,能夠自動(dòng)處理對(duì)象的生命周期,確保對(duì)象在超出作用域時(shí)被銷毀。QScopedPointer 是基于 C++11 標(biāo)準(zhǔn)中的 std::unique_ptr 實(shí)現(xiàn)的,但它具有 Qt 的特點(diǎn),通常用于局部對(duì)象的管理。
- 自動(dòng)刪除對(duì)象:當(dāng)
QScopedPointer超出作用域時(shí),它會(huì)自動(dòng)釋放所持有的對(duì)象。這意味著無(wú)需手動(dòng)delete對(duì)象。 - 不能復(fù)制:
QScopedPointer不支持復(fù)制操作,防止發(fā)生意外的多個(gè)指針指向同一個(gè)對(duì)象的問(wèn)題。 - 所有權(quán)轉(zhuǎn)移:可以使用
reset()或通過(guò)構(gòu)造函數(shù)將QScopedPointer的所有權(quán)轉(zhuǎn)移給另一個(gè)QScopedPointer。
1. 自動(dòng)刪除對(duì)象
QScopedPointer 最常見(jiàn)的用法是在函數(shù)或局部作用域內(nèi)管理動(dòng)態(tài)分配的對(duì)象。在作用域結(jié)束時(shí),QScopedPointer 自動(dòng)銷毀對(duì)象,無(wú)需顯式調(diào)用 delete。
#include <QScopedPointer>
#include <QDebug>
class MyClass {
public:
MyClass() { qDebug() << "MyClass constructed"; }
~MyClass() { qDebug() << "MyClass destructed"; }
};
void testScopedPointer() {
QScopedPointer<MyClass> ptr(new MyClass);
// 當(dāng)函數(shù)返回時(shí),ptr 超出作用域,對(duì)象會(huì)被自動(dòng)銷毀
} // 在這里,MyClass 對(duì)象會(huì)被自動(dòng)刪除
2. 轉(zhuǎn)移所有權(quán)
QScopedPointer 不支持復(fù)制操作,但可以通過(guò) reset() 或構(gòu)造函數(shù)轉(zhuǎn)移所有權(quán)。這樣,QScopedPointer 可以在不同的作用域之間傳遞資源。
#include <QScopedPointer>
#include <QDebug>
class MyClass {
public:
MyClass() { qDebug() << "MyClass constructed"; }
~MyClass() { qDebug() << "MyClass destructed"; }
};
void transferOwnership() {
QScopedPointer<MyClass> ptr1(new MyClass);
// 將所有權(quán)從 ptr1 轉(zhuǎn)移到 ptr2
QScopedPointer<MyClass> ptr2(ptr1.take());
// 現(xiàn)在 ptr1 不再擁有 MyClass 對(duì)象,ptr2 擁有它
// ptr1 不再指向?qū)ο螅珜?duì)象仍然存在,由 ptr2 管理
} // 在這里,ptr2 超出作用域時(shí),MyClass 對(duì)象會(huì)被自動(dòng)刪除
3. 管理私有數(shù)據(jù)
在 Qt 的許多類中,私有數(shù)據(jù)(通常是一個(gè)包含實(shí)現(xiàn)細(xì)節(jié)的類)被封裝在一個(gè) QScopedPointer 中。這樣可以確保私有數(shù)據(jù)在類的析構(gòu)函數(shù)中自動(dòng)釋放,同時(shí)保持代碼的簡(jiǎn)潔性和安全性。
示例:QFile 類
class QFilePrivate : public QIODevicePrivate {
// 私有數(shù)據(jù)成員
};
class QFile : public QIODevice {
public:
QFile();
~QFile();
private:
QScopedPointer<QFilePrivate> d_ptr;
};
在這個(gè)例子中,QFile 類使用 QScopedPointer 來(lái)管理 QFilePrivate 對(duì)象。當(dāng) QFile 對(duì)象析構(gòu)時(shí),QScopedPointer 會(huì)自動(dòng)刪除 QFilePrivate 對(duì)象,確保內(nèi)存被釋放。
QSharedPointer
QSharedPointer 是通過(guò)引用計(jì)數(shù)來(lái)管理對(duì)象的生命周期的,多個(gè) QSharedPointer 對(duì)象可以共享同一個(gè)資源。每當(dāng) QSharedPointer 的拷貝構(gòu)造或賦值操作發(fā)生時(shí),引用計(jì)數(shù)會(huì)增加,而當(dāng)一個(gè) QSharedPointer 被銷毀時(shí),引用計(jì)數(shù)會(huì)減少。當(dāng)引用計(jì)數(shù)降到 0 時(shí),所指向的對(duì)象會(huì)自動(dòng)被刪除。
#include <QSharedPointer>
#include <QDebug>
class MyClass {
public:
void print() { qDebug() << "Hello from MyClass!"; }
};
int main() {
// 創(chuàng)建 QSharedPointer 對(duì)象,管理 MyClass 對(duì)象的生命周期
QSharedPointer<MyClass> ptr1(new MyClass);
// 創(chuàng)建另外一個(gè) QSharedPointer,并共享 ptr1 所管理的對(duì)象
QSharedPointer<MyClass> ptr2 = ptr1;
// 使用 ptr1 和 ptr2 都能訪問(wèn)同一個(gè)對(duì)象
ptr1->print();
ptr2->print();
// 不需要手動(dòng)釋放內(nèi)存,當(dāng)最后一個(gè) QSharedPointer 被銷毀時(shí),MyClass 對(duì)象會(huì)自動(dòng)刪除
return 0;
}
關(guān)鍵特性
- 引用計(jì)數(shù):
QSharedPointer通過(guò)引用計(jì)數(shù)來(lái)管理對(duì)象的生命周期。每當(dāng)有新的QSharedPointer對(duì)象指向相同的資源時(shí),引用計(jì)數(shù)會(huì)增加;當(dāng)某個(gè)QSharedPointer對(duì)象銷毀時(shí),引用計(jì)數(shù)會(huì)減少。 - 自動(dòng)銷毀:當(dāng)最后一個(gè)引用計(jì)數(shù)為 1 的
QSharedPointer被銷毀時(shí),指向的對(duì)象會(huì)被自動(dòng)刪除,從而避免了內(nèi)存泄漏。 - 線程安全:
QSharedPointer的引用計(jì)數(shù)操作是線程安全的,但它本身并不保證被指向的對(duì)象本身是線程安全的。如果多個(gè)線程訪問(wèn)同一個(gè)QSharedPointer對(duì)象,必須確保其他線程同步訪問(wèn)該對(duì)象。
注意事項(xiàng)
QSharedPointer的引用計(jì)數(shù)機(jī)制在某些情況下可能導(dǎo)致循環(huán)引用問(wèn)題,特別是當(dāng)兩個(gè)或更多的對(duì)象相互持有對(duì)方的QSharedPointer時(shí)。此時(shí),即使這些對(duì)象不再使用,引用計(jì)數(shù)也不會(huì)降到零,因?yàn)樗鼈兓ハ嘁?,?dǎo)致對(duì)象無(wú)法被銷毀,從而產(chǎn)生內(nèi)存泄漏。解決方法:使用
QWeakPointer來(lái)打破循環(huán)引用。QWeakPointer是一種弱引用,持有一個(gè)QSharedPointer對(duì)象,但它不會(huì)增加引用計(jì)數(shù)。當(dāng)QSharedPointer被銷毀時(shí),QWeakPointer自動(dòng)變?yōu)榭罩羔槨?/p>- 不要混用裸指針和
QSharedPointer``QSharedPointer需要確保它是唯一的內(nèi)存管理者。如果你在程序中同時(shí)使用裸指針和QSharedPointer管理相同的內(nèi)存,可能會(huì)導(dǎo)致雙重釋放或內(nèi)存泄漏。因此,避免裸指針與智能指針共享同一資源,確保對(duì)象始終由智能指針管理。
QWeakPointer
QWeakPointer 是 QSharedPointer 的一種補(bǔ)充,它本身不擁有對(duì)象的所有權(quán)。QWeakPointer 僅在 QSharedPointer 的引用計(jì)數(shù)為非零時(shí)提供訪問(wèn)該對(duì)象的能力,但不會(huì)阻止對(duì)象的銷毀。換句話說(shuō),QWeakPointer 允許你引用一個(gè)對(duì)象而不會(huì)使得該對(duì)象無(wú)法銷毀。
QWeakPointer 的主要特點(diǎn):
- 弱引用:
QWeakPointer不增加對(duì)象的引用計(jì)數(shù),也就是說(shuō)它不會(huì)阻止對(duì)象的銷毀。 - 防止循環(huán)引用:
QWeakPointer解決了QSharedPointer可能導(dǎo)致的循環(huán)引用問(wèn)題。 - 安全的訪問(wèn)方式:
QWeakPointer可以通過(guò)toStrongRef()方法轉(zhuǎn)換為QSharedPointer,從而安全地訪問(wèn)目標(biāo)對(duì)象。
QWeakPointer 和 QSharedPointer 的配合
QWeakPointer 通常與 QSharedPointer 一起使用,用于避免循環(huán)引用。在有些情況下,兩個(gè)對(duì)象會(huì)互相引用,導(dǎo)致它們的引用計(jì)數(shù)始終不為零,進(jìn)而導(dǎo)致內(nèi)存泄漏。QWeakPointer 可以打破這個(gè)循環(huán)引用鏈,它允許對(duì)象 A 持有對(duì)象 B 的 QWeakPointer,而對(duì)象 B 可以持有對(duì)象 A 的 QSharedPointer,從而確保對(duì)象 A 和 B 的生命周期由 QSharedPointer 管理。
QWeakPointer 的常見(jiàn)用法
下面是一個(gè)使用 QWeakPointer 的具體示例:
class B; // Forward declaration
class A {
public:
QSharedPointer<B> b; // B的共享指針
};
class B {
public:
QWeakPointer<A> a; // A的弱引用
};
int main() {
QSharedPointer<A> a(new A); // 創(chuàng)建A對(duì)象
QSharedPointer<B> b(new B); // 創(chuàng)建B對(duì)象
a->b = b; // A持有B的共享指針
b->a = a; // B持有A的弱引用
return 0; // 程序退出時(shí),A和B會(huì)被自動(dòng)銷毀,避免內(nèi)存泄漏
}
注意事項(xiàng)
使用QWeakPointer時(shí)候,一定要使用isNULL判斷一下 資源是否釋放
QSharedPointer<MyClass> shared(new MyClass(20));
QWeakPointer<MyClass> weak(shared);
qDebug() << "Shared pointer value:" << shared->getValue();
qDebug() << "Weak pointer value:" << weak.data()->getValue();
shared.clear(); // 刪除 shared 指向的對(duì)象
// 此時(shí),MyClass 對(duì)象的引用計(jì)數(shù)為 0,將被自動(dòng)刪除,而此時(shí) QWeakPointer 對(duì)象 weak 也為 null。
if (weak.isNull()) { // 判斷 weak 是否為 null
qDebug() << "Weak pointer is null - object has been deleted"; // 執(zhí)行
}
else {
qDebug() << "Weak pointer is not null - object still exists";
}
QPointer
QPointer 是一個(gè)用于指向 Qt 對(duì)象(例如 QObject 的子類)的模板類,它會(huì)自動(dòng)管理對(duì)象的生命周期。當(dāng)一個(gè) QObject 被銷毀時(shí),QPointer 會(huì)將其指針設(shè)為 nullptr,這使得程序能夠檢測(cè)到所指向的對(duì)象已經(jīng)被刪除,從而避免訪問(wèn)已刪除的對(duì)象,避免懸空指針問(wèn)題。QPointer 只能用來(lái)管理 QObject 或其子類的對(duì)象。如果你需要管理其他類型的對(duì)象,可以考慮使用其他智能指針,如 std::shared_ptr 或 std::unique_ptr。
#include <QPointer>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QWidget window;
QVBoxLayout *layout = new QVBoxLayout(&window);
QPushButton *button = new QPushButton("Click me");
QPointer<QPushButton> pButton(button);
layout->addWidget(button);
window.show();
QObject::connect(button, &QPushButton::clicked, [&] {
if (pButton) {
qDebug() << "Button exists, text:" << pButton->text();
} else {
qDebug() << "Button has been deleted";
}
});
// 模擬按鈕刪除
QObject::connect(button, &QPushButton::clicked, [&] {
delete button;
});
return a.exec();
}到此這篇關(guān)于Qt 智能指針的具體使用的文章就介紹到這了,更多相關(guān)Qt 智能指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++數(shù)據(jù)結(jié)構(gòu)與算法的基礎(chǔ)知識(shí)和經(jīng)典算法匯總
終是到了標(biāo)志著大二結(jié)束的期末考試了,對(duì)于《算法設(shè)計(jì)與分析》這門課,我需要總結(jié)一下學(xué)過(guò)的所有算法的思想以及老師補(bǔ)充的關(guān)于兩個(gè)復(fù)雜度和遞歸的概念思想,以及更深層次的理解,比如用畫圖的方式表達(dá)出來(lái),我覺(jué)得可以用博客記錄總結(jié)一下,分享給大家,希望能有所幫助2022-05-05
深入了解C語(yǔ)言的動(dòng)態(tài)內(nèi)存管理
所謂動(dòng)態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動(dòng)態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文將用5600字帶你深入了解動(dòng)態(tài)內(nèi)存管理,感興趣的可以學(xué)習(xí)一下2022-07-07
剖析C++編程當(dāng)中指針作為函數(shù)參數(shù)的用法
這篇文章主要介紹了剖析C++編程當(dāng)中指針作為函數(shù)參數(shù)的用法,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09
C++?STL中五個(gè)常用算法使用教程及實(shí)例講解
本文主要介紹了C++?STL算法中常見(jiàn)的五個(gè)算法的使用教程并附上了案例詳解,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-11-11
Qt中const?QString轉(zhuǎn)換?char?*可能的坑
本文主要介紹了Qt中const?QString轉(zhuǎn)換?char?*可能的坑,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
Qt實(shí)現(xiàn)界面滑動(dòng)切換效果的思路詳解
這篇文章主要介紹了Qt實(shí)現(xiàn)界面滑動(dòng)切換效果,主要包括設(shè)計(jì)思路及主要函數(shù)講解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07
VS2019開發(fā)簡(jiǎn)單的C/C++動(dòng)態(tài)鏈接庫(kù)并進(jìn)行調(diào)用的實(shí)現(xiàn)
這篇文章主要介紹了VS2019開發(fā)簡(jiǎn)單的C/C++動(dòng)態(tài)鏈接庫(kù)并進(jìn)行調(diào)用的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03

