回顾下前面提到的Android 轻量级智能指针 LightRefBase:
class Person : public LightRefBase<Person>{}
sp<Person>{
.Person *mptr;
sp(){
incStrong;
}
~sp(){
decStrong;
}
}
类比,强弱指针可能会有如下统一实现:
class RefBase{
private:
int mStrong;
int mWeak;
Public:
void incStrong();
void decStrong();
void incWeak();
void decWeak();
}
进一步抽象剥离:
StrongWeakRef_type mRefs;
class StrongWeakRef_type{
private:
int mStrong;
int mWeak;
Public:
//void incStrong(); //为了保持兼容,这两个方法保留在class RefBase中
//void decStrong();
void incWeak();
void decWeak();
}
实际开发中涉及到多个模块相互调用时,使用者常常是引用对方的头文件,使用者在头文件中往往不想看到private属性的mStrong和mWeak,只想知道可以调用的Public接口。我们想到的优化方法是,将一个类拆成两部分:1)固定接口类;2)容易变化的实现类。具体如下:
//抽象为接口类。放在头文件中。
class weakRef_type{
public:
void incWeak();
void decWeak();
}
//独立为实现类。放在cpp文件中。
class weakRef_impl : public weakRef_type {
int mStrong;
int mWeak;
}
开发中,cpp文件可以编译成库文件,使用者可以使用头文件和库文件即可。
进一步推测,class RefBase部分内容如下:
class RefBase{
/* 为什么不能是包含成员变量而是包含指针变量呢?
* 因为一旦weakRef_impl的实现发生变化,比如新增和减少内容,
* 会导致包含它的所有者的内存布局也发生变化,而仅包含指针的话没有这个问题。
*/
//weakref_impl mRefs;
weakref_impl * mRefs;
}
看一下Android对统一的强弱指针的实现–class RefBase,验证一下:
//frameworks/rs/cpp/util/RefBase.h
template <typename T>
class wp
{
...
private:
...
weakref_type* m_refs;
}
//system/core/libutils/RefBase.cpp
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatile int32_t mStrong;
volatile int32_t mWeak;
...
}
使用Anroid强弱指针:
class Person: public RefBase{}
//强指针
sp<Person>{
sp(){incStrong();}
~sp(){decStrong();}
}
//弱指针
wp<Person>{
wp(){incWeak();}
~wp(){decWeak();}
}
使用上一节“Android 弱指针的引入”的例子,将使用轻量级智能指针改成使用强指针:
//class Person : public LightRefBase{
class Person : public RefBase<Person>{
private:
sp<Person> father;
sp<Person> son;
。。。
}
验证结果也一样–目标对象在main函数/test_func函数调用结束时没有被销毁。
将强指针改成弱指针,此问题解决:
//class Person : public LightRefBase{
class Person : public RefBase<Person>{
private:
wp<Person> father;
wp<Person> son;
。。。
}
进一步看下强弱指针的使用:
int main(int argc, char **argv)
{
wp<Person> s = new Person();
//s->printInfo(); /* 出错, 注意:wp没有重载"->", "*" */
//(*s).printInfo(); /* 出错, 注意:wp没有重载"->", "*" */
sp<Person> s2 = s.promote(); //弱指针升级成强指针
if (s2 != 0) {
s2->printInfo();
}
return 0;
}
再看个例子:
#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 setFather(sp<Person> &father)
{
this->father = father;
}
void setSon(sp<Person> &son)
{
this->son = son;
}
char *getName(void)
{
return name;
}
void printInfo(void)
{
sp<Person> f = father.promote();//(1)
sp<Person> s = son.promote();
cout<<"I am "<<name<<endl;
if (f != 0)//(2)
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");
sp<Person> son = new Person("LiErShi");
father->setSon(son);
son->setFather(father);
father->printInfo();
son->printInfo();
}
int main(int argc, char **argv)
{
test_func();
return 0;
}
可以看到,使用弱指针wp就不会导致相互引用时产生死锁导致双方都不能释放对象的问题。但是对于弱指针wp,若想调用目标对象中的某些方法时,比如像(1)使用promote方法把它升级为强指针;且(2)升级完后要判断返回值,因为弱指针只是简单的引用某个对象而已,并不保证对象是否消亡。另外,Android 强指针的实现原理与前面讲的轻量级智能指针是类似的。
若要继续分析Android实现强弱指针的源码,需要注意如下两点:
1)mFlags:
OBJ_LIFETIME_STRONG:表示对象生命周期由mStrong决定;
OBJ_LIFETIME_WEAK:表示对象生命周期由mWeak决定;
2)mStrong <= mWeak
参考:韦东山C++教程