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中哈希表的

这也就是单基类的好处,可以在这里控制很多事情

http://blog.csdn.net/oowgsoo/article/details/1529424

Qt源码分析之QPointer的更多相关文章

  1. Qt源码分析之QObject

    原文:http://blog.csdn.net/oowgsoo/article/details/1529284 我感觉oowgsoo兄弟写的分析相当透彻,赞! 1.试验代码: #include < ...

  2. QT源码分析(从QApplication开始)

    QT源码分析 转载自:http://no001.blog.51cto.com/1142339/282130 今天,在给同学讲东西的时候,谈到了Qt源代码的问题,才发现自己对Qt机制的了解是在太少了,而 ...

  3. QT源码分析:QTcpServer

    最近在看有关IO复用方面的内容,自己也用标准c++库实现了select模型.iocp模型.poll模型.回过头来很想了解QT的socket是基于什么模型来实现的,所以看了QT关于TcpServer实现 ...

  4. QT源码分析:QObject

    QT框架里面最大的特色就是在C++的基础上增加了元对象系统(Meta-Object System),而元对象系统里面最重要的内容就是信号与槽机制,这个机制是在C++语法的基础上实现的,使用了函数.函数 ...

  5. Qt源码分析之信号和槽机制

    Qt的信号和槽机制是Qt的一大特点,实际上这是和MFC中的消息映射机制相似的东西,要完成的事情也差不多,就是发送一个消息然后让其它窗口响应,当然,这里的消息是广义的说法,简单点说就是如何在一个类的一个 ...

  6. Qt源码分析之信号和槽机制(QMetaObject是一个内部struct)

    Qt的信号和槽机制是Qt的一大特点,实际上这是和MFC中的消息映射机制相似的东西,要完成的事情也差不多,就是发送一个消息然后让其它窗口响应,当然,这里的消息是广义的说法,简单点说就是如何在一个类的一个 ...

  7. QT 源码分析--1

    Ref: http://blog.sina.com.cn/s/blog_6e80f1390100qoc0.html 安装qt之后(我使用的是online自动安装),安装目录下有\5.10.1\Src\ ...

  8. Qt之使用setWindowFlags方法遇到的问题(追踪进入QWidget的源码分析原因,最后用WINAPI解决问题)good

    一.简述 前段时间在使用setWindowFlags方法时遇到了一个坑,具体情况是想通过窗口界面上一个checkBox来控制窗口当前状态是否置顶,而Qt提供了Qt::WindowStaysOnTopH ...

  9. Qt update刷新之源码分析(一)

    在做GUI开发时,要让控件刷新,会调用update函数:那么在调用了update函数后,Qt究竟基于什么原理.执行了什么代码使得屏幕上有变化?本文就带大家来探究探究其内部源码. Qt手册中关于QWid ...

随机推荐

  1. 使用PDO连接多种数据库

    在PHP 5之前,想要连接MySQL数据库就需要使用mysql或mysqli等一系列函数来操作数据库.例如,我们使用mysql系列数据库函数进行查询操作,对应的示例代码如下: <?php //创 ...

  2. entityframework多条件查询类

    entityframework多条件查询类 var dataaccess = new BaseAccess(); int totalCount = 0; var paramS = new OrderM ...

  3. AppDelegate 方法详解

    iOS 程序启动时总会调用application:didFinishLaunchingWithOptions:,其中第二个参数launchOptions为NSDictionary类型的对象,里面存储有 ...

  4. ORACLE 关连更新 update select

    总结:  关键的地方是where 语句的加入. 在11G中, 如果不加11G , 或造成除匹配的行数更新为相应的值之后, 其余的会变成负数. 所以, 测试的办法就是:  先查看需要更新的数量即连接的数 ...

  5. BCEC手动验证业务方法

    在每次割接或业务调整后手动执行并做好业务验证工作 一.研发区利用ansible手动执行巡检程序: 步骤1:登陆 10.254.3.4/opt/ansible 步骤2:手动执行 sh compute_c ...

  6. Codevs 1427 特种部队(双路DP)

    1427 特种部队 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 黄金 Gold 题目描述 Description 某特种部队接到一个任务,需要潜入一个仓库.该部队士兵分为两路,第一 ...

  7. IniParse解析类

    说明 iniParse这个类是一个解析ini文件的类,他的功能和Windows下GetPrivateProfileString的功能一样,可以很方便的保存读取配置. 当然他不是只有GetPrivate ...

  8. (转)UIColor 的使用

    os开发-UIColor的使用. 在ios开发中,经常遇到对UIColor的相关操作. 比如这样 self.backgroundColor = [UIColorredColor]; 这里的redCol ...

  9. leetcode problem (5) Longest Palindromic Substring

    最长回文子串: 1. 暴力搜索   时间复杂度O(n^3) 2. 动态规划 dp[i][j] 表示子串s[i…j]是否是回文 初始化:dp[i][i] = true (0 <= i <= ...

  10. C++11中新特性之:initializer_list详解

    C++11提供的新类型,定义在<initializer_list>头文件中. template< class T > class initializer_list; 先说它的用 ...