智能指针

C/C++项目中常见的指针问题可以归纳为:

1. 指针没有初始化

对指针进行初始化是程序员必须养成的良好习惯,也是指针问题中最容易解决和控制的一个(其实不仅是指针的初始化,新分配的内存块在进行操作前都应视实际情况进行初始化)

2. new 了对象后没有及时delete

3.野指针

智能指针就是用来解决这三个问题的

那么智能指针应该如何设计呢

SmartPointer应该是一个模板类

template <typename T>
class SmartPointer
{
    inline SmartPointer():m_ptr(0) {}
    private:
        T * m_ptr;
}

智能指针怎么知道该什么时候释放掉一个内存对象呢,这就需要引用计数来实现

那引用计数应该由谁管理,智能指针拥有的话就会导致如下问题:

如果两个智能指针同时指向同一个对象,那么其中一个智能指针的引用计数为0是就会释放掉这个对象,另一个智能指针还在使用这个对象的话,就会引发致命的问题

解决的唯一方法就是 引用计数由Object拥有

我们可以让所有的对象都继承于这个拥有计数功能的父类,如下方这个例子

template <class T>
class LightRefBase
{
public:
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(__attribute__((unused)) const void* id) const {
        __sync_fetch_and_add(&mCount, 1);
    }
    inline void decStrong(__attribute__((unused)) const void* id) const {
        if (__sync_fetch_and_sub(&mCount, 1) == 1) {
            delete static_cast<const T*>(this);
        }
    }
    //! DEBUGGING ONLY: Get current strong ref count.
    inline int32_t getStrongCount() const {
        return mCount;
    }

    typedef LightRefBase<T> basetype;

protected:
    inline ~LightRefBase() { }

private:
    friend class ReferenceMover;
    inline static void moveReferences(void*, void const*, size_t,
            const ReferenceConverterBase&) { }

private:
    mutable volatile int32_t mCount;
};

incStrong和decStrong分别用于增加和减少引用计数值,那这两个函数在什么情况下被调用呢?既然是引用计数,当然是在被引用时,这个工作有SmartPointer来完成

SmartPointer<TYPE> smartP = new object;

当一个智能指针引用了object时,其父类的incStrong就会被调用。所有SmartPointer必须重载它的“=“运算符。

template<typename T>

SmartPointer <T> & SmartPointer<T>::operator = (T *other) {

    if(other != NULL) {
        m_ptr = other;//指向内存对象
        other->incStrong();//增加引用计数值
    }
    return *this;
}

当SmartPointer析构时,也应该及时调用decStrong来释放引用;

在Android中其实存在sp(强指针)和wp(弱指针)之分

sp的定义在StrongPointer.h (rs\cpp\util)   ,wp的定义在RefBase.h (rs\cpp\util) 

template <typename T>
class sp
{
public:
    inline sp() : m_ptr(0) { }

    sp(T* other);  // NOLINT, implicit
    sp(const sp<T>& other);
    template<typename U> sp(U* other);  // NOLINT, implicit
    template<typename U> sp(const sp<U>& other);  // NOLINT, implicit

    ~sp();

    // Assignment

    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);

    template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (U* other);

    //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other);

    // Reset

    void clear();

    // Accessors

    inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }

    // Operators

    COMPARE(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=)

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
};

sp模板类的实现跟StrongPointer比较相似。也比较好理解

为什么又提出了个弱指针,其使用场景又是什么呢;

考虑如下场景:父对象parent指向子对象child,然后子对象又指向了父对象,这就存在循坏引用的情况

struct Dad
{
    Child * myChild;
};

struct Child
{
    Dad * myDad;
}

如果没有智能指针,这样的情况不会导致任何问题,若有智能指针,就会出现内存死锁

解决这个问题的有效方法就是使用弱指针来实现

Dad使用强指针来引用Child,而Child使用弱引用来指向Dad。双方规定档强引用计数为0时,不论若引用计数是否为0,都可以delete自己(在Android中这个规则是可以改变的),这样一方得到了释放,就可以成功避免内存死锁,但这样会导致Child指向的Dad对象不存在的话,引出野指针问题,可以用以下方式避免:

弱指针必须先升级为强指针,才能访问它所指向的目标对象

弱指针主要就是解决循坏引用的问题

template <typename T>
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;

    inline wp() : m_ptr(0) { }

    explicit wp(T* other);
    wp(const wp<T>& other);
    explicit wp(const sp<T>& other);
    template<typename U> explicit wp(U* other);
    template<typename U> explicit wp(const sp<U>& other);
    template<typename U> explicit wp(const wp<U>& other);

    ~wp();

    // Assignment

    wp& operator = (T* other);
    wp& operator = (const wp<T>& other);
    wp& operator = (const sp<T>& other);

    template<typename U> wp& operator = (U* other);
    template<typename U> wp& operator = (const wp<U>& other);
    template<typename U> wp& operator = (const sp<U>& other);

    void set_object_and_refs(T* other, weakref_type* refs);

    // promotion to sp

    sp<T> promote() const;//升级为强指针

    // Reset

    void clear();

    // Accessors

    inline  weakref_type* get_refs() const { return m_refs; }

    inline  T* unsafe_get() const { return m_ptr; }

    // Operators

    COMPARE_WEAK(==)
    COMPARE_WEAK(!=)
    COMPARE_WEAK(>)
    COMPARE_WEAK(<)
    COMPARE_WEAK(<=)
    COMPARE_WEAK(>=)

    inline bool operator == (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
    }
    template<typename U>
    inline bool operator == (const wp<U>& o) const {
        return m_ptr == o.m_ptr;
    }

    inline bool operator > (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }
    template<typename U>
    inline bool operator > (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }

    inline bool operator < (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
    template<typename U>
    inline bool operator < (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
                         inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
    template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
                         inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
    template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
                         inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
    template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;

    T*              m_ptr;
    weakref_type*   m_refs;//另外一个指向m_refs的指针
};

wp的构造函数

template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
{
    if (other) m_refs = other->createWeak(this);
}

createWeak是RefBase的方法,weakref_type是RefBase的一个内部嵌套类

 class weakref_type
    {
    public:
        RefBase*            refBase() const;

        void                incWeak(const void* id);
        void                decWeak(const void* id);

        // acquires a strong reference if there is already one.
        bool                attemptIncStrong(const void* id);

        // acquires a weak reference if there is already one.
        // This is not always safe. see ProcessState.cpp and BpBinder.cpp
        // for proper use.
        bool                attemptIncWeak(const void* id);

        //! DEBUGGING ONLY: Get current weak ref count.
        int32_t             getWeakCount() const;

        //! DEBUGGING ONLY: Print references held on object.
        void                printRefs() const;

        //! DEBUGGING ONLY: Enable tracking for this object.
        // enable -- enable/disable tracking
        // retain -- when tracking is enable, if true, then we save a stack trace
        //           for each reference and dereference; when retain == false, we
        //           match up references and dereferences and keep only the
        //           outstanding ones.

        void                trackMe(bool enable, bool retain);
    };

RefBase还有一个weakref_impl;其实现在system//core/libutils/RefBase.cpp中

class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
    std::atomic<int32_t>    mStrong;//强引用计数值
    std::atomic<int32_t>    mWeak;//弱引用计数值
    RefBase* const          mBase;
    std::atomic<int32_t>    mFlags;
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);//增加弱引用计数
    return mRefs;//直接返回weakref_type对象
}

mRefs也就是weakref_impl类型的成员变量,这个函数增加了弱引用计数,然后返回这个mRefs。

和LightRefBase不同,RefBase不是直接使用int变量来保存引用计数,而是采用了weakref_type类型的计数器。因为RefBase需要处理多种计数类型。wp中的m_refs和RefBase中的mRefs都指向了计数器。wp通过createWeak获得计数器的地址,而计数器本身是有RefBase在构造时创建的

RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}

整个wp机制很复杂,但中心都是围绕着新的计数器weakref_impl而已

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值