• Qt源码分析之QPointer


    原文:http://blog.csdn.net/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中哈希表的

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

  • 相关阅读:
    vue集成百度UEditor富文本编辑器
    HTTPS访问站点,出现证书问题解决(转载) 规格严格
    JSSE 提供的 动态 debug 追踪模式 规格严格
    javax.net.debug 规格严格
    Oralce null 规格严格
    pipe 规格严格
    (总结)ibatis 动态传入表名和列名 规格严格
    垃圾回收算法简介 规格严格
    转载(正则表达式的分类) 规格严格
    长度为0的数组 规格严格
  • 原文地址:https://www.cnblogs.com/hicjiajia/p/2155516.html
Copyright © 2020-2023  润新知