Qt源码剖析-智能指针

4 篇文章 0 订阅

目录

智能指针是什么?

为什么使用QT智能(smart)指针?

Qt提供了哪些智能指针?

QSharedPointer类模板(smart指针类)源码分析

1. QSharedPointer类模板对于模板参数T的类型重定义

2. QSharedPointer的成员属性

3. QtSharedPointer::ExternalRefCountData声明&定义

4. CustomDeleter& ExternalRefCountWithCustomDeleter 的声明&定义

5. QSharedPointer的构造&析构

6. QSharedPointer 静态创建方法create

7. QSharedPointer 拷贝构造&与重载赋值运算符

8. QSharedPointer针对指针管理、操作成员函数

9. QSharedPointer 清理&重置

10. QSharedPointer类型转换函数

QSharedPointer UML类图

结尾


智能指针是什么?

1. 智能指针是使用RAII技术(惯用手法)对裸指针进行封装、隔离、管理。

2. 把堆对象转移为栈对象。

为什么使用QT智能(smart)指针?

CPP中在使用堆内存时我们必须使用指针,使用指针给我带来便利和强大的威力同时也给我们带来了很多隐患,所以指针也是把双刃剑。

常见的隐患有:

1. 我们在使用new创建一个对象的同时,由于种种原因而忘记了delete从而导致内存泄漏影响应用运行效率

2. 我们在使用一个指针的时候不知道该指针指向的对象是否已经析构,从而导致使用一个错误的野指针。

针对上述问题Qt提供一组类模板(Smart指针类)来管理C++中的裸指针, 同时提供相关重载运算符使得使用起来与指针操作无异。 指针的生命周期也交由Smart类来管理而不用程序员自己去手动管理。使用Smart指针进而避免了上述隐患的存在。

Qt提供了哪些智能指针?

QPointer、QSharedPointer、QScopedPointer、QWeakPointer、QSharedDataPointer、QExplicitlySharedDataPointer、QGuard、QtPatternist::AutoPtr


由于Qt智能指针较多,避免篇幅较长本文只对平时使用场景较多的QSharedPointer源码进行分析也比较有代表性

QSharedPointer 官方介绍:

QSharedPointer类持有对共享指针的强引用。QSharedPointer是c++中的一个自动共享指针。它的行为与用于普通目的的普通指针完全相同,包括对constness的尊重。当指针超出作用域时,QSharedPointer将删除它所持有的指针,前提是没有其他QSharedPointer对象引用它。QSharedPointer对象可以从普通指针、另一个QSharedPointer对象或通过将QWeakPointer对象提升为强引用来创建。

本文基于Qt5.12.4版本分析

QSharedPointer类模板(smart指针类)源码分析

QSharedPointer类源码篇幅较长,避免出现阅读疲劳以下分段解读。

1. QSharedPointer类模板对于模板参数T的类型重定义

template <class T> class QSharedPointer
{
    typedef T *QSharedPointer:: *RestrictedBool;
    typedef QtSharedPointer::ExternalRefCountData Data;
public:
    typedef T Type;
    typedef T element_type;
    typedef T value_type;
    typedef value_type *pointer;
    typedef const value_type *const_pointer;
    typedef value_type &reference;
    typedef const value_type &const_reference;
    typedef qptrdiff difference_type;
};

QSharedPointer提供了部分公有和私有的对于模板参数T的类型重定义(说明: 这里T类型并不是指一个特定类型,而是一个通用/万能类型。 我们可以把类模板看做成一个函数 QSharedPointer为函数名, template中类型列表的为函数形参列表,typedef 为返回值。 T最终的类型确认待你使用时由编译器实例化模板时才能推导出),QSharedPointer类模板分别重定义了模板入参T的类型别名、指针、常指针、引用、常引用类型。这也是模板的惯用手法和伎俩方便对于类型的获取和使用

原因有以下几点:

a. 提供公有的对于T的类型重定义方便的类外部获取和使用T及其衍生类型。

b. 类内部实现过程中统一,规范对于T的使用。

2. QSharedPointer的成员属性

template <class T> class QSharedPointer
{
    // @1
    Type *value;
    // @2
    Data *d;
};

QSharedPointer成员属性比较简洁代码段@1声明成员属性value(需要管理的裸指针), 代码段@2声明属性d。Data类型我们从第1点中可知为QtSharedPointer::ExternalRefCountData 的类型别名。主要作用为记录当前持有value的QSharedPointer对象数量和销毁QSharedPointer封装的指针。

3. QtSharedPointer::ExternalRefCountData声明&定义

    struct ExternalRefCountData
    {
        typedef void (*DestroyerFn)(ExternalRefCountData *);
        QBasicAtomicInt weakref;
        QBasicAtomicInt strongref;
        DestroyerFn destroyer;

        inline ExternalRefCountData(DestroyerFn d)
            : destroyer(d)
        {
            strongref.store(1);
            weakref.store(1);
        }
        inline ExternalRefCountData(Qt::Initialization) { }
        ~ExternalRefCountData() { Q_ASSERT(!weakref.load()); Q_ASSERT(strongref.load() <= 0); }

        void destroy() { destroyer(this); }

#ifndef QT_NO_QOBJECT
        Q_CORE_EXPORT static ExternalRefCountData *getAndRef(const QObject *);
        Q_CORE_EXPORT void setQObjectShared(const QObject *, bool enable);
        Q_CORE_EXPORT void checkQObjectShared(const QObject *);
#endif
        inline void checkQObjectShared(...) { }
        inline void setQObjectShared(...) { }

        inline void operator delete(void *ptr) { ::operator delete(ptr); }
        inline void operator delete(void *, void *) { }
    };

可以看出ExternalRefCountData结构是用于管理指针计数用的,ExternalRefCountData结构中weakref、strongref这两个成员属性命名我们观察出一个用于强引用计数一个用于弱引用计数,从QBaseAtomicInt类型可以看出这是一个原子的Int类型,所以引用计数的数量计量器是一个线程安全的类型。

strongref 是内部指针的引用计数器,它跟踪指针本身的生命周期。

weakref是外部引用计数器,它跟踪对象的生存期。 用于解决QSharedPointer循环引用问题。

weakref的使用更多体现在QWeakPointer模板类中。

destroyer为一个回调函数指针,用于ExternalRefCountData 在destroy方法中回调。 从下文中我们会发现destroyer函数指针总是指向ExternalRefCountWithCustomDeleter或externalrefcountwithcontinuousdata结构得静态方法deleter or safetyCheckDeleter。

4. CustomDeleter& ExternalRefCountWithCustomDeleter 的声明&定义

// @1
template <class T, typename Klass, typename RetVal>
inline void executeDeleter(T *t, RetVal (Klass:: *memberDeleter)())
{ (t->*memberDeleter)(); }

// @2
template <class T, typename Deleter>
inline void executeDeleter(T *t, Deleter d)
{ d(t); }

// @3
struct NormalDeleter {};

// 

template <class T, typename Deleter>
    struct CustomDeleter
    {
        Deleter deleter;
        T *ptr;

        CustomDeleter(T *p, Deleter d) : deleter(d), ptr(p) {}
        void execute() { executeDeleter(ptr, deleter); }
    };
    // sizeof(CustomDeleter) = sizeof(Deleter) + sizeof(void*) + padding
    // for Deleter = stateless functor: 8 (32-bit) / 16 (64-bit) due to padding
    // for Deleter = function pointer:  8 (32-bit) / 16 (64-bit)
    // for Deleter = PMF: 12 (32-bit) / 24 (64-bit)  (GCC)

    // This specialization of CustomDeleter for a deleter of type NormalDeleter
    // is an optimization: instead of storing a pointer to a function that does
    // the deleting, we simply delete the pointer ourselves.
    template <class T>
    struct CustomDeleter<T, NormalDeleter>
    {
        T *ptr;

        CustomDeleter(T *p, NormalDeleter) : ptr(p) {}
        void execute() { delete ptr; }
    };
    // sizeof(CustomDeleter specialization) = sizeof(void*)

    // This class extends ExternalRefCountData and implements
    // the static function that deletes the object. The pointer and the
    // custom deleter are kept in the "extra" member so we can construct
    // and destruct it independently of the full structure.
    template <class T, typename Deleter>
    struct ExternalRefCountWithCustomDeleter: public ExternalRefCountData
    {
        typedef ExternalRefCountWithCustomDeleter Self;
        typedef ExternalRefCountData BaseClass;
        
        // @4
        CustomDeleter<T, Deleter> extra;
        
        // @5
        static inline void deleter(ExternalRefCountData *self)
        {
            Self *realself = static_cast<Self *>(self);
            realself->extra.execute();

            // delete the deleter too
            realself->extra.~CustomDeleter<T, Deleter>();
        }
        
        // @6
        static void safetyCheckDeleter(ExternalRefCountData *self)
        {
            internalSafetyCheckRemove(self);
            deleter(self);
        }
        
        // @7
        static inline Self *create(T *ptr, 
                                    Deleter userDeleter, 
                                    DestroyerFn actualDeleter)
        {
            Self *d = static_cast<Self *>(::operator new(sizeof(Self)));

            // initialize the two sub-objects
            new (&d->extra) CustomDeleter<T, Deleter>(ptr, userDeleter);
            new (d) BaseClass(actualDeleter); // can't throw

            return d;
        }
    private:
        // @8
        // prevent construction
        ExternalRefCountWithCustomDeleter() Q_DECL_EQ_DELETE;
        ~ExternalRefCountWithCustomDeleter() Q_DECL_EQ_DELETE;
        Q_DISABLE_COPY(ExternalRefCountWithCustomDeleter)
    };

CustomDeleter结构模板封装了一个指针与可调用类型(函数指针)。 当执行CustomDeleter结构的 execute方法时及调用全局executeDeleter函数的调用,当函数指针为类的成员方法则调用代码段@1 否则调用代码段@2. 同时CustomDeleter结构模板还偏特化了Deleter类型模板参数,如果模板参数Deleter 为类型代码段@3 NormalDeleter结构时在执行CustomDeleter execute函数时直接delete CustomDeleter当前封装的指针ptr。这里可以看出来该结构主要作用是用来销毁QSharedPointer封装的指针。 至于具体怎么使用, 需结合ExternalRefCountWithCustomDeleter和QSharedPointer构造来看,这里先说有这个东西待下文提到时能知道有这个结构以及作用。

ExternalRefCountWithCustomDeleter结构模板为第3点中ExternalRefCountData的扩展(派生)结构。对CustomDeleter也进行了二次封装,组合了CustomDeleter结构。对CustomDeleter的操作都是由ExternalRefCountWithCustomDeleter触发的。

首先我们看看这个结构做了些什么:

a. 模板参数T&Deleter 被转发到成员属性 extra中 见代码@4 CustomDeleter<T, Deleter>

b. 代码@5 声明了一个静态的deleter 删除器方法,接收一个当前结构的父结构指针。 函数体实现中 将形参父结构指针强制转换为当前类型(ExternalRefCountWithCustomDeleter)指针,在调用成员extra CustomDeleter中的execute方法,最后手动调用CustomDeleter 析构函数。 由此可知该方法就是执行CustomDeleter中的回调方法然后对CustomDeleter 进行销毁的一个过程。

c. 当启用了QT_SHAREDPOINTER_TRACK_POINTERS预编译宏时,ExternalRefCountData的成员destroyer则指向该静态方法。

 Qt 对于QT_SHAREDPOINTER_TRACK_POINTERS解释:

QSharedPointer指针跟踪机制, 可以在编译时为调试目的启用的特性。启用后,QSharedPointer 将其跟踪的所有指针注册到全局集合中。这允许人们捕捉错误,例如将相同的指针分配给两个 QSharedPointer 对象。通过在包含 QSharedPointer 标头之前定义 QT_SHAREDPOINTER_TRACK_POINTERS 宏来启用此功能。
即使编译没有该功能的代码,也可以安全地使用此功能。 QSharedPointer 将确保指针从跟踪器中删除,即使是从没有指针跟踪的情况下编译的代码。
但是请注意,指针跟踪功能对多重或虚拟继承有限制(即在两个不同的指针地址可以引用同一个对象的情况下)。在这种情况下,如果一个指针被转换为不同的类型并且它的值发生了变化,QSharedPointer 的指针跟踪机制可能无法检测到被跟踪的对象是相同的。

d. 代码段@7声明了一个静态的create方法,用于构建ExternalRefCountWithCustomDeleter对象。函数形参为模板T类型的指针、模板参数Deleter类型的可调用对象、DestroyerFn函数指针。函数体中进行的ExternalRefCountWithCustomDeleter的构造,是基于定位new来构造的。 先从堆上获取一块与自己尺寸大小相等的内存,在分配到的首地址d的extra偏移量处初始化CustomDeleter时把形参1&2转发到该构造函数中。最后在分配内存的起始位置上构造出父结构(C++ 对象内存布局,父类成员属性地址位于子类前)。至此完成了ExternalRefCountWithCustomDeleter的构造。

e. 代码段@8 禁用了该结构得拷贝构造&默认构造&析构。

5. QSharedPointer的构造&析构

template <class T> class QSharedPointer
{
    // @1
    Q_DECL_CONSTEXPR QSharedPointer() Q_DECL_NOTHROW : 
        value(nullptr), d(nullptr) {
    }
    
    // @2
    ~QSharedPointer() { deref(); }

    // @3
    Q_DECL_CONSTEXPR QSharedPointer(std::nullptr_t) Q_DECL_NOTHROW : 
        value(nullptr), d(nullptr) { 
    }

    // @4
    template <class X>
    inline explicit QSharedPointer(X *ptr) : value(ptr) // noexcept
    { internalConstruct(ptr, QtSharedPointer::NormalDeleter()); }

    // @5
    template <class X, typename Deleter>
    inline QSharedPointer(X *ptr, Deleter deleter) : value(ptr) // throws
    { internalConstruct(ptr, deleter); }
    
    // @6
    template <typename Deleter>
    QSharedPointer(std::nullptr_t, Deleter) : value(nullptr), d(nullptr) { }

    void deref() Q_DECL_NOTHROW
    { deref(d); }
    static void deref(Data *dd) Q_DECL_NOTHROW
    {
        if (!dd) return;
        if (!dd->strongref.deref()) {
            dd->destroy();
        }
        if (!dd->weakref.deref())
            delete dd;
    }

    
    // @7
    template <typename X, typename Deleter>
    inline void internalConstruct(X *ptr, Deleter deleter)
    {
        if (!ptr) {
            d = nullptr;
            return;
        }

        typedef QtSharedPointer::ExternalRefCountWithCustomDeleter<X, Deleter> Private;
# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
        typename Private::DestroyerFn actualDeleter = &Private::safetyCheckDeleter;
# else
        typename Private::DestroyerFn actualDeleter = &Private::deleter;
# endif
        d = Private::create(ptr, deleter, actualDeleter);

#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
        internalSafetyCheckAdd(d, ptr);
#endif
        d->setQObjectShared(ptr, true);
        enableSharedFromThis(ptr);
    }


};

a. 代码段@1&3构造函数接收无参或nullptr,初始化成员value&d为nullptr。简单的实例化QSharedPointer对象不管理指针。

b. 代码段@4&5 构造函数都需要传递一个待封装的裸指针,且在初始化列表中使用形参ptr对成员属性value赋初值。 代码段@5还需要传入一个删除器(Deleter)实参,代码段@4 函数体中给出了第4点中代码段@3中的一个默认空的删除器对象。  

c. 代码段@7 internalConstruct函数接收从代码段@4&5构造函数中传入的实参,此处我们只分析预编译宏QT_SHAREDPOINTER_TRACK_POINTERS未定义的情况。重定义第4点中ExternalRefCountWithCustomDeleter模板结构为Private类型,并实例化ExternalRefCountWithCustomDeleter模板结构的模板参数T为当前封装裸指针的类型、模板参数Deleter为NormalDeleter或由客户代码构造时指定的删除器类型。执行ExternalRefCountWithCustomDeleter 静态Create函数,实参分别为当前待封装的裸指针ptr、构造函数代码段@4&5 传入的Deleter、ExternalRefCountWithCustomDeleter结构下的静态函数deleter地址。create函数的具体实现参阅第4点。最后由QSharedPointer成员属性d指向create创建的ExternalRefCountWithCustomDeleter实例。 至此就完成了QSharedPointer对象的构造。

d. 代码段@2析构函数: 析构函数体中调用deref函数, deref函数对当前QSharedPointer对象成员d的引用计数进行减1. 因为QSharedPointer自己被销毁了便不再对value指针进行持有。如果成员d下的strongref为0 则调用ExternalRefCountData 结构下的destroy函数。参阅c段我们知道对于destory的调用实际为对ExternalRefCountWithCustomDeleter结构静态函数deleter的调用。deleter方法的作用可以参阅第4点b段,执行自定义删除器方法的回调(构造时如果传入),执行ExternalRefCountWithCustomDeleter属性extra 析构函数。 如果成员d下的weakref 为0 则delete d。

6. QSharedPointer 静态创建方法create

template <typename... Args>
    static QSharedPointer create(Args && ...arguments)
    {
        // @1
        typedef QtSharedPointer::ExternalRefCountWithContiguousData<T> Private;
# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
        typename Private::DestroyerFn destroy = &Private::safetyCheckDeleter;
# else
        typename Private::DestroyerFn destroy = &Private::deleter;
# endif
        typename Private::DestroyerFn noDestroy = &Private::noDeleter;
        QSharedPointer result(Qt::Uninitialized);
        typename std::remove_cv<T>::type *ptr;
        result.d = Private::create(&ptr, noDestroy);

        // now initialize the data
        new (ptr) T(std::forward<Args>(arguments)...);
        result.value = ptr;
        result.d->destroyer = destroy;
        result.d->setQObjectShared(result.value, true);
# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
        internalSafetyCheckAdd(result.d, result.value);
# endif
        result.enableSharedFromThis(result.data());
        return result;
    }

由函数实现内容看, 形参列表由模板参数包数量与类型指定。 参与包对对应着QSharedPointer模板参数T类型的构造形参列表。 create是一个便捷的构造QSharedPointer对象方法,省去了我们在外部去创建一个特定的指针。

create函数实现体:

a. 基于 私有 explicit QSharedPointer(Qt::Initialization) {}构造函数构造一个局部QSharedPointer对象result。 Qt::Initialization并无实际意义仅仅是为了重载默认构造函数

b. 代码段@1处为重定义ExternalRefCountWithContiguousData 结构模板为Private类型。

ExternalRefCountWithContiguousData声明&定义:

template <class T>
    struct ExternalRefCountWithContiguousData: public ExternalRefCountData
    {
        typedef ExternalRefCountData Parent;
        typedef typename std::remove_cv<T>::type NoCVType;
        NoCVType data;

        static void deleter(ExternalRefCountData *self)
        {
            ExternalRefCountWithContiguousData *that =
                    static_cast<ExternalRefCountWithContiguousData *>(self);
            that->data.~T();
            Q_UNUSED(that); // MSVC warns if T has a trivial destructor
        }
        static void safetyCheckDeleter(ExternalRefCountData *self)
        {
            internalSafetyCheckRemove(self);
            deleter(self);
        }
        static void noDeleter(ExternalRefCountData *) { }

        static inline ExternalRefCountData *create(NoCVType **ptr, DestroyerFn destroy)
        {
            ExternalRefCountWithContiguousData *d =
                static_cast<ExternalRefCountWithContiguousData *>(::operator new(sizeof(ExternalRefCountWithContiguousData)));

            // initialize the d-pointer sub-object
            // leave d->data uninitialized
            new (d) Parent(destroy); // can't throw

            *ptr = &d->data;
            return d;
        }

    private:
        // prevent construction
        ExternalRefCountWithContiguousData() Q_DECL_EQ_DELETE;
        ~ExternalRefCountWithContiguousData() Q_DECL_EQ_DELETE;
        Q_DISABLE_COPY(ExternalRefCountWithContiguousData)
    };

这个结构扩展了ExternalRefCountData并添加了一个“T”成员。T类型即为QSharedPointer模板类的参数最终就是待封装的指针类型,当调用create()函数时,我们为QSharedPointer的d指针和被跟踪的实际对象分配内存。函数内部在分配内存的同时构造父类部分,成员T的构造(即待封装的指针实例)会留到函数返回后进行构造。new (ptr) T(std::forward<Args>(arguments)...)

c. QSharedPointer 对象的成语属性d的实际类型由ExternalRefCountWithCustomDeleter 转换为ExternalRefCountWithContiguousData。

与ExternalRefCountWithCustomDeleter 相比ExternalRefCountWithContiguousData结构不再使用CustomDeleter结构来管理QSharedPointer所封装的指针,而是组合T类型实例,使用定位new来构造T类型,最终在自己deleter静态函数中实现资源的销毁。

7. QSharedPointer 拷贝构造&与重载赋值运算符

template <class T> class QSharedPointer
{

    // @1
    QSharedPointer(const QSharedPointer &other) Q_DECL_NOTHROW : 
        value(other.value), d(other.d)
    { if (d) ref(); }

    // @2
    QSharedPointer &operator=(const QSharedPointer &other) Q_DECL_NOTHROW
    {
        QSharedPointer copy(other);
        swap(copy);
        return *this;
    }

#ifdef Q_COMPILER_RVALUE_REFS
    // @7
    QSharedPointer(QSharedPointer &&other) Q_DECL_NOTHROW
        : value(other.value), d(other.d)
    {
        other.d = nullptr;
        other.value = nullptr;
    }
    
    // @8
    QSharedPointer &operator=(QSharedPointer &&other) Q_DECL_NOTHROW
    {
        QSharedPointer moved(std::move(other));
        swap(moved);
        return *this;
    }

    // @9
    template <class X>
    QSharedPointer(QSharedPointer<X> &&other) Q_DECL_NOTHROW
        : value(other.value), d(other.d)
    {
        other.d = nullptr;
        other.value = nullptr;
    }
    
    // @10
    template <class X>
    QSharedPointer &operator=(QSharedPointer<X> &&other) Q_DECL_NOTHROW
    {
        QSharedPointer moved(std::move(other));
        swap(moved);
        return *this;
    }

#endif

    // @3
    template <class X>
    QSharedPointer(const QSharedPointer<X> &other) Q_DECL_NOTHROW
        : value(other.value), d(other.d)
    { if (d) ref(); }

    // @4
    template <class X>
    inline QSharedPointer &operator=(const QSharedPointer<X> &other)
    {
        QSharedPointer copy(other);
        swap(copy);
        return *this;
    }

    // @5
    template <class X>
    inline QSharedPointer(const QWeakPointer<X> &other)
        : value(nullptr), d(nullptr)
    { *this = other; }

    // @6
    template <class X>
    inline QSharedPointer<T> &operator=(const QWeakPointer<X> &other)
    { internalSet(other.d, other.value); return *this; }

    void ref() const Q_DECL_NOTHROW { 
        d->weakref.ref(); d->strongref.ref(); 
    }

    inline void swap(QSharedPointer &other) { 
        this->internalSwap(other); 
    }
    
    void internalSwap(QSharedPointer &other) Q_DECL_NOTHROW
    {
        qSwap(d, other.d);
        qSwap(this->value, other.value);
    }
};

a. 代码段@1拷贝构造函数: 当前待构造的QSharedPointer对象持有的裸指针value与指针持有的QSharedPointer数量计数对象d与other对象一致,只做简单的成员浅拷贝。即当前构造的QSharedPointer对象与other QSharedPointer对象成员属性value&d都指向同一块内存。 由于当前新构造的QSharedPointer增加了对value指针的持有, 所以d计数对象下的weakref & strongref都原子安全递增1。

b. 代码段@2重载赋值运算符:  从赋值运算符的操作行为上看我们可以知道,操作完成后左操作数QSharedPointer对象的成员d的引用计数需减1,右操作数QSharedPointer对象的成员d的引用计数需加1. 函数实现体中首先基于other对象拷贝构造了copy对象,此时copy对象的成员value&d与other指向相同,但d的引用计数已经累加1,在调用swap函数, 把copy对象的成员value&d直接交换到左操作数对象, 左操作数对象原有的value&d交换给copy对象,待函数执行完成函数栈被销毁时,copy对象(原有左操作数对象)成员d的引用计数减1顺利完成QSharedPointer对象的赋值操作。

c. 代码段@3&4提供了拷贝构造&赋值操作的模板重载版本,匹配value指针类型隐式类型转换版本。实现与@1&2相同。

Q_COMPILER_RVALUE_REFS预编译宏中定义的拷贝构造与重载赋值操作符的右值版本及移动拷贝构造与移动赋值。

d. 代码段@7移动拷贝构造:把other右值对象持有的d&value拷贝给当前对象,但引用计数无需加1. 因为构造完成后右值就不存了。 

e. 代码段@8 移动赋值: 同理moved对象的生成会调用@7,不会对other对象引用计数加1. 后续逻辑同代码段@2

f. 代码段@9&10 提供了右值拷贝构造&赋值的重载版本,实现与代码段@7&8相同。

8. QSharedPointer针对指针管理、操作成员函数

template <class T> class QSharedPointer
{
public:
    T *data() const Q_DECL_NOTHROW { return value; }
    T *get() const Q_DECL_NOTHROW { return value; }
    bool isNull() const Q_DECL_NOTHROW { return !data(); }
    operator RestrictedBool() const Q_DECL_NOTHROW { return isNull() ? nullptr : &QSharedPointer::value; }
    bool operator !() const Q_DECL_NOTHROW { return isNull(); }
    T &operator*() const { return *data(); }
    T *operator->() const Q_DECL_NOTHROW { return data(); }
};

Qt在成员函数声明末尾都添加了Q_DECL_NOTHROW 宏,Q_DECL_NOTHROW宏即为C++11 关键字noexcept,C++11建议对于明确不会抛出异常的函数应在函数声明默尾添加此关键字,目的是是的编译器更加聪明的去优化该函数用来提升程序性能。

成员函数:

a. data&get函数都只是简单的返回当前持有的value裸指针。

b. 运算符*、->的重载使得操作QSharedPointer对象与操作裸指针行为表现一致. !运算符的重载用于逻辑运算判断当前QSharedPointer对象持有的指针是否为nullptr。

c. QSharedPointer类型到RestrictedBool类型隐式转换重载, RestrictedBool类型为类型(T *QSharedPointer:: *)的别名,第一点中有给出。 最终为取value T* 的地址。

9. QSharedPointer 清理&重置

template <class T> class QSharedPointer
{
    inline void reset() { clear(); }
    inline void reset(T *t)
    { QSharedPointer copy(t); swap(copy); }
    template <typename Deleter>
    inline void reset(T *t, Deleter deleter)
    { QSharedPointer copy(t, deleter); swap(copy); }
    inline void clear() { QSharedPointer copy; swap(copy); }
};

a. reset() 函数重置当前持有为nullptr,并把原有持有的d引用计数值减1

b. reset(T* ) 函数重置当前持有的指针为t,释放原有持有。 并把原有持有的d引用计数值减1

c. reset(T *t, Deleter deleter) 函数重置为当前持有的指针为t

10. QSharedPointer类型转换函数

全局转换函数

template <class X, class T>
QSharedPointer<X> qSharedPointerCast(const QSharedPointer<T> &ptr);
template <class X, class T>
QSharedPointer<X> qSharedPointerDynamicCast(const QSharedPointer<T> &ptr);
template <class X, class T>
QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &ptr);

#ifndef QT_NO_QOBJECT
template <class X, class T>
QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &ptr);
#endif

上面4个转换函数分别对应着把当前QSharedPointer对象ptr封装的T类型裸指针转换为封装成X类型的QSharedPointer对象。 

qSharedPointerCast、qSharedPointerDynamicCast、qSharedPointerConstCast 函数内部分别对应C++ static_cast、dynamic_cast、const_cast类型转换函数

qSharedPointerObjectCast 函数对应为Qt提供的qobject_cast 类型转换函数

成员转换函数

template <class X>
    QSharedPointer<X> staticCast() const
    {
        return qSharedPointerCast<X, T>(*this);
    }

    template <class X>
    QSharedPointer<X> dynamicCast() const
    {
        return qSharedPointerDynamicCast<X, T>(*this);
    }

    template <class X>
    QSharedPointer<X> constCast() const
    {
        return qSharedPointerConstCast<X, T>(*this);
    }

#ifndef QT_NO_QOBJECT
    template <class X>
    QSharedPointer<X> objectCast() const
    {
        return qSharedPointerObjectCast<X, T>(*this);
    }
#endif

对全局转换类型函数的二次封装,由于待转换的QSharedPointer为本身,默认填充了全局类型转换函数的实参为自己提供了使用上的便利性。

QSharedPointer UML类图

结尾

鉴于篇幅原因本文欠缺对QSharedPointer&QWeakPointer互相使用的分析,对于QSharedPointer的源码分析是为了更好的使用Smart指针类、了解其背后的运作原理、 学习如何通过分析源码提升自己更好的去设计出一个健全、稳定、高效的类。感谢阅读(#^.^#)

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值