QPointer對象的實(shí)現(xiàn)如下,其中我們可以看到榨乎,QPointer在構(gòu)造時(shí)创译,模板類型不能是指針(通過c++的偏特化特性來判斷是否傳入類型為指針)。其次是對象的成員QWeakPointer叁熔,QPointer是對QWeakPointer進(jìn)行封裝,使得QWeakPointer比較簡單易用床牧。因此荣回,在探尋QPointer為啥能夠在QObject析構(gòu)時(shí),自動置為nullptr戈咳,其實(shí)底層原理實(shí)際在QWeakPointer中實(shí)現(xiàn)心软。
class QPointer
{
Q_STATIC_ASSERT_X(!std::is_pointer<T>::value, "QPointer's template type must not be a pointer type");
...
QWeakPointer<QObjectType> wp;
public:
inline QPointer() { }
inline QPointer(T *p) : wp(p, true) { }
...
};
QPointer構(gòu)造一個(gè)指針對象時(shí),QWeakPointer調(diào)用的構(gòu)造函數(shù)為
inline QWeakPointer(X *ptr, bool) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr)
Data::getAndRef的具體實(shí)現(xiàn)如下著蛙,獲取ptr對象的引用計(jì)算删铃,返回弱引用指針:
QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::getAndRef(const QObject *obj)
{
Q_ASSERT(obj);
QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj));
Q_ASSERT_X(!d->wasDeleted, "QWeakPointer", "Detected QWeakPointer creation in a QObject being deleted");
ExternalRefCountData *that = d->sharedRefcount.load();
if (that) {
that->weakref.ref();
return that;
}
// we can create the refcount data because it doesn't exist
ExternalRefCountData *x = new ExternalRefCountData(Qt::Uninitialized);
x->strongref.store(-1);
x->weakref.store(2); // the QWeakPointer that called us plus the QObject itself
ExternalRefCountData *ret;
if (d->sharedRefcount.testAndSetOrdered(nullptr, x, ret)) { // ought to be release+acquire; this is acq_rel+acquire
ret = x;
} else {
// ~ExternalRefCountData has a Q_ASSERT, so we use this trick to
// only execute this if Q_ASSERTs are enabled
Q_ASSERT((x->weakref.store(0), true));
delete x;
ret->weakref.ref();
}
return ret;
}
QWeakPointer的默認(rèn)構(gòu)造會自動置nullptr,因此踏堡,使用QPointer作為成員變量時(shí)猎唁,不需要額外初始化為nullptr
inline QPointer() { }
inline QWeakPointer() Q_DECL_NOTHROW : d(nullptr), value(nullptr) { }
QSharedPointer中的引用計(jì)數(shù)對象也是ExternalRefCountData,QObjectPrivate中的ExternalRefCountData和QSharedPointer中記錄對象的ExternalRefCountData有一些區(qū)別顷蟆,盡管它們的用途和機(jī)制都與引用計(jì)數(shù)有關(guān)诫隅。
1. QObjectPrivate::ExternalRefCountData
QObjectPrivate 中的 ExternalRefCountData 是 QObject 用來管理其外部引用計(jì)數(shù)的結(jié)構(gòu)缎患。QObject 對象的外部引用計(jì)數(shù)用于管理對象的生命周期,特別是在對象被外部引用時(shí)防止其被過早刪除阎肝。這個(gè)引用計(jì)數(shù)主要與事件循環(huán)挤渔、信號槽機(jī)制以及一些特殊的QObject派生類相關(guān)聯(lián)。
QObjectPrivate 中的 ExternalRefCountData 通過引用計(jì)數(shù)跟蹤外部對該 QObject 的引用风题。當(dāng)引用計(jì)數(shù)為0時(shí)判导,QObject 可以安全地銷毀。
這部分機(jī)制主要是在Qt的內(nèi)存管理和QObject生命周期管理中起作用沛硅。2. QSharedPointer::ExternalRefCountData
QSharedPointer 中的 ExternalRefCountData 是智能指針機(jī)制的一部分眼刃,用于管理指針的引用計(jì)數(shù)。QSharedPointer 是一個(gè)智能指針類摇肌,提供了自動的內(nèi)存管理擂红,通過引用計(jì)數(shù)來決定對象的刪除時(shí)間。
當(dāng)多個(gè) QSharedPointer 指向同一對象時(shí)围小,這個(gè)對象的引用計(jì)數(shù)會增加昵骤。只有當(dāng)最后一個(gè) QSharedPointer 被銷毀或者重置時(shí),指向的對象才會被刪除肯适。
QSharedPointer::ExternalRefCountData 管理的引用計(jì)數(shù)不僅僅是對象本身的引用变秦,還包括指向同一對象的所有 QSharedPointer 實(shí)例的引用。
QWeakPointer獲取所指對象QObjectPrivate的弱引用框舔,對象指針獲取和判空時(shí)蹦玫,都會 d->strongref.load()判斷所指對象的強(qiáng)引用計(jì)數(shù),通過強(qiáng)引用計(jì)數(shù)來判斷對象是否還存在刘绣。
bool isNull() const Q_DECL_NOTHROW { return d == nullptr || d->strongref.load() == 0 || value == nullptr; }
T *data() const Q_DECL_NOTHROW { return d == nullptr || d->strongref.load() == 0 ? nullptr : value; }
那么樱溉,QObjectPrivate中的sharedRefcount是怎么維護(hù)的呢?
在QObject::~QObject()中纬凤,會獲取QObjectPrivate中的sharedRefcount福贞,并且設(shè)置 sharedRefcount->strongref.store(0)為0,QWeakPointers在跟蹤這個(gè)對象時(shí)移斩,會通過判斷strongref為0時(shí)來確認(rèn)該對象是否被銷毀肚医,sharedRefcount的實(shí)際銷毀時(shí)機(jī)在最后一個(gè)weakref.deref()時(shí)绢馍。
QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.load();
if (sharedRefcount) {
if (sharedRefcount->strongref.load() > 0) {
qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash.");
// but continue deleting, it's too late to stop anyway
}
// indicate to all QWeakPointers that this QObject has now been deleted
sharedRefcount->strongref.store(0);
if (!sharedRefcount->weakref.deref())
delete sharedRefcount;
}
inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; }
因此向瓷,sharedRefcount->strongref.store(0),是QWeakPointer判斷所指對象是否被銷毀的依據(jù)舰涌,QObjectPrivate的ExternalRefCountData 在Data::getAndRef時(shí)被初始化猖任,在QObject::~QObject()時(shí),sharedRefcount->strongref.store(0)瓷耙,標(biāo)記對象被銷毀朱躺。通過引用計(jì)數(shù)的形式刁赖,進(jìn)行對象跟蹤。