原文:http://blog.youkuaiyun.com/oowgsoo/article/details/1529424
QPointer是一个指针封装类,其作用类似于智能指针,但是它最大的特点应该是在指针的控制上,它希望一个Qt的指针(当然是从QObject派生的)可以同时被多个类拥有,这在
界面编程中当然是很常见的事情了,但是当这个指针被删除时,我们不希望再找到那两个界面类然后通知它们,相反我们希望这两个界面类可以直接判断QPointer中的isNull方法
很自然的知道原始指针已经不存在了
1.试验代码:
#include <QApplication> #include <QPushButton> #include <QPointer> int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton* pButton = new QPushButton("wgs"); QPointer<QPushButton> button = pButton; delete pButton; if (!button.isNull()) { button->setText("www"); } return app.exec(); }
一段很短的代码,这里需要的注意的是QPointer指针的使用
template <class T> class QPointer { QObject *o; public: inline QPointer() : o(0) {} inline QPointer(T *p) : o(p) { QMetaObject::addGuard(&o); } inline QPointer(const QPointer<T> &p) : o(p.o) { QMetaObject::addGuard(&o); } inline ~QPointer() { QMetaObject::removeGuard(&o); } inline QPointer<T> &operator=(const QPointer<T> &p) { if (this != &p) QMetaObject::changeGuard(&o, p.o); return *this; } inline QPointer<T> &operator=(T* p) { if (o != p) QMetaObject::changeGuard(&o, p); return *this; } inline bool isNull() const { return !o; } inline T* operator->() const { return static_cast<T*>(const_cast<QObject*>(o)); } inline T& operator*() const { return *static_cast<T*>(const_cast<QObject*>(o)); } inline operator T*() const { return static_cast<T*>(const_cast<QObject*>(o)); } };
QPointer只是一个简单的模板,对QMetaObject的相关操作做了简单的封装,这里的基本思想是
在QPointer构造的时候调用QMetaObject::addGuard(&o),把T的指针加入QMetaObject内的一个哈希表中,
在QPointer析构的时候调用QMetaObject::removeGuard(&o),把T的指针从哈希表中删除
这是一个QMetaObject中静态成员,该哈希表的定义如下:
typedef QMultiHash<QObject *, QObject **> GuardHash;
这个哈希表存储的是指针的值和指针的地址,因此加入的代码如下:
void QMetaObject::addGuard(QObject **ptr) { if (!*ptr) return; GuardHash *hash = guardHash(); if (!hash) { *ptr = 0; return; } QWriteLocker locker(guardHashLock()); hash->insert(*ptr, ptr); }
为什么不是只保存一个指针呢,原来是为了防止误删除,看看删除的代码:
void QMetaObject::removeGuard(QObject **ptr) { if (!*ptr) return; GuardHash *hash = guardHash(); if (!hash) return; QWriteLocker locker(guardHashLock()); GuardHash::iterator it = hash->find(*ptr); const GuardHash::iterator end = hash->end(); for (; it.key() == *ptr && it != end; ++it) { if (it.value() == ptr) { (void) hash->erase(it); break; } } }
只有在it.value() == ptr的时候才会删除
但是等等,当删除普通指针时又如何更新这个哈希表呢?
delete pButton;如何通知QMetaObject中的哈希表更新?
答案是在QObject中,请注意QObject的析构函数
QObject::~QObject() { Q_D(QObject); if (d->wasDeleted) { #if defined(QT_DEBUG) qWarning("Double QObject deletion detected"); #endif return; } d->wasDeleted = true; d->blockSig = 0; // unblock signals so we always emit destroyed() // set all QPointers for this object to zero GuardHash *hash = ::guardHash(); if (hash) { QWriteLocker locker(guardHashLock()); GuardHash::iterator it = hash->find(this); const GuardHash::iterator end = hash->end(); while (it.key() == this && it != end) { *it.value() = 0; it = hash->erase(it); } } emit destroyed(this); QConnectionList *list = ::connectionList(); if (list) { QWriteLocker locker(&list->lock); list->remove(this); } if (d->pendTimer) { // have pending timers QThread *thr = thread(); if (thr || d->thread == 0) { // don't unregister timers in the wrong thread QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(thr); if (eventDispatcher) eventDispatcher->unregisterTimers(this); } } d->eventFilters.clear(); // delete children objects if (!d->children.isEmpty()) { qDeleteAll(d->children); d->children.clear(); } { QWriteLocker locker(QObjectPrivate::readWriteLock()); ::qt_removeObject(this); /* theoretically, we cannot check d->postedEvents without holding the postEventList.mutex for the object's thread, but since we hold the QObjectPrivate::readWriteLock(), nothing can go into QCoreApplication::postEvent(), which effectively means noone can post new events, which is what we are trying to prevent. this means we can safely check d->postedEvents, since we are fairly sure it will not change (it could, but only by decreasing, i.e. removing posted events from a differebnt thread) */ if (d->postedEvents > 0) QCoreApplication::removePostedEvents(this); } if (d->parent) // remove it from parent object d->setParent_helper(0); delete d; d_ptr = 0; }
这里做了很多很多的事情,其中的代码
// set all QPointers for this object to zero GuardHash *hash = ::guardHash(); if (hash) { QWriteLocker locker(guardHashLock()); GuardHash::iterator it = hash->find(this); const GuardHash::iterator end = hash->end(); while (it.key() == this && it != end) { *it.value() = 0; it = hash->erase(it); } }
就是更新QMetaObject中哈希表的
这也就是单基类的好处,可以在这里控制很多事情

993

被折叠的 条评论
为什么被折叠?



