安卓轻量级智能指针

文章目录

    • 1.安卓轻量级智能指针
    • 2.指针互相引用带来死锁问题
    • 3.安卓弱指针的引进
    • 4.修改代码,引入弱指针

1.安卓轻量级智能指针

在c++智能指针的简单实现与改进中实现了简单的智能指针,但是还是存在缺陷,当多线程操作RefBase中引用的值时得到的可能不是我们想要的,这是由于对RefBase中的引用计数非原子性导致,在Android中实现了轻量级智能指针保证了对引用计数的原子性

安卓源码路径:

frameworks/rs/cpp/util/RefBase.h

实现:

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;
};

注意点:

__sync_fetch_and_add(&mCount, 1):对引用计数加1

 if (__sync_fetch_and_sub(&mCount, 1) == 1) { 
           delete static_cast<const T*>(this); 
       }

先用__sync_fetch_and_sub(&mCount, 1) == 1进行减1操作,使用该函数返回的是mCount被减去1之前的值,即此时mCount为0,返回值为1,会将目标对象进行删除操作,实际上还存在着问题,轻量级智能指针保证了对引用计数的原子性,但无法保证对目标对象的销毁,当执行__sync_fetch_and_sub(&mCount, 1) == 1刚好线程被切换出去,刚好此线程对对象进行赋值操作,后面切换回来将对象删除。所以需要程序员自己去考虑如何使用

2.指针互相引用带来死锁问题

下面一个程序存在一个问题,对象之间互相引用导致程序结束对象依旧没有销毁

#include 
#include 
#include 
#include "RefBase.h"

using namespace std;
using namespace android::RSC;

class Person : public LightRefBase<Person>{
private:
   sp<Person> father;
   sp<Person> son;

public:
   Person() {
       cout <<"Pserson()"<<endl;
   }


   ~Person()
   {
       cout << "~Person()"<<endl;
   }

   void set_father(sp<Person> &father)
   {
       this->father = father;
   }

   void set_son(sp<Person> &son)
   {
       this->son = son;
   }
   
   void print_info(void)
   {
       cout<<"just for test"<<endl;
   }
};

void test_func()
{
   sp<Person> father = new Person();
   sp<Person> son = new Person();
   father->set_son(son);
   son->set_father(father);
}

int main(int argc, char **argv)
{    
   test_func();
   return 0;
}

需要注意的点:

  1. 如果对象中含有其他对象成员时,先构造其他对象成员,再构造自身,所以在sp father = new Person(); sp son = new Person(),都先构造father和son,再构建person自身
  2. 再将person对象的指针传给sp father或者sp son,从而调用 sp(T* other) ,增加了person对象的引用计数(此时值为1)
  3. 调用set_father或者set_son操作会使自身的person对象引用计数+1,此时计数为2
  4. 当test_func函数结束时,father和son被析构,对于father来说,调用~sp()之后引用计数减1,此时引用计数为1,对son也是如此,所以father和son这两个对象都没有被销毁

存在问题:

  • 对象father和son互相引用,决定对方的生死,这种引用方式叫做强引用,要想解决强引用带来的对象无法销毁,只有引入弱引用才可以解决,解决的办法是一个使用强指针,一个使用弱指针
  • 强引用/强指针:A指向B,A决定B的生死
  • 弱引用/弱指针:A指向B,A不能决定B的生死

3.安卓弱指针的引进

csdn已经有很多优秀的博客讲解强弱指针,可以参考下面文章
Android 系统C++智能指针----总结
Android基础–智能指针

4.修改代码,引入弱指针

#include 
#include 
#include 
#include 

using namespace std;
using namespace android;

class Person : public RefBase {

private:
    char *name;
    
    wp<Person> father;
    wp<Person> son;

public:
    Person() {
        cout <<"Pserson()"<<endl;
    }

    Person(char *name) {
        cout <<"Pserson(char *name)"<<endl;
        this->name = name;
    }

    ~Person()
    {
        cout << "~Person()"<<endl;
    }

    void set_father(sp<Person> &father)
    {
        this->father = father;
    }

    void set_son(sp<Person> &son)
    {
        this->son = son;
    }

    char *get_name(void)
    {
        return name;
    }
    
    void print_info(void)
    {
        sp<Person> f = father.promote();
        sp<Person> s = son.promote();
        
        cout<<"I am "<<name<<endl;

        if (f != 0)
            cout<<"My Father is "<<f->getName()<<endl;

        if (s != 0)
            cout<<"My Son is "<<s->getName()<<endl;
    }
};

void test_func()
{
    sp<Person> father = new Person("LiYiShi");//1
    sp<Person> son = new Person("LiErShi");//2

    father->set_son(son);//3

    son->set_father(father);//4
}

int main(int argc, char **argv)
{    
    test_func();
    return 0;
}

结果:

~Person()
~Person()

可以看到两个person对象都调用了析构函数

  1. 1,2过程会使两个Person对象的强引用计数+1,弱引用计数加1
  2. 3,4过程会使两个person对象的弱引用+1
  3. 所以函数结束之后会调用两个对象的析构函数,强引用计数减为0

注意:

  • 但是对于弱指针wp,若想调用目标对象中的某些方法时,需要使用promote方法把它升级为强指针,升级完后要判断返回值,因为弱指针只是简单的引用某个对象而已,并不保证对象已经消亡

你可能感兴趣的:(C++基础知识,android,c++,开发语言)