Android 浅析 智能指针

前言

Linus Benedict Torvalds : RTFSC – Read The Funning Source Code

设计理念

为了避免像C++指针里的常见问题而重新设计更“安全”的指针。C++中常见的问题:1、指针没初始化;2、new了后忘记delete;3、野指针。

指针类型

Android中定义了两种智能指针类型,一种是强指针sp(strong pointer),另外一种是弱指针(weak pointer)

强指针sp(strong pointer):
与一般意义的智能指针概念相同,通过引用计数来记录有多少使用者在使用一个对象,如果所有使用者都放弃了对该对象的引用,则该对象将被自动销毁。

弱指针(weak pointer):
弱指针也指向一个对象,但是弱指针仅仅记录该对象的地址,不能通过弱指针来访问该对象,也就是说不能通过弱指针来调用对象的成员函数或访问对象的成员变量。

指针类实现

如果要使用智能指针来引用这个类的对象,那么这个类需满足下列两个前提条件:
1:这个类是基类RefBase的子类或间接子类;
2:这个类必须定义虚构造函数,即它的构造函数需要这样定义:virtual ~MyClass();

轻量级引用计数类LightRefBase

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template <class T>
class LightRefBase
{
public:
inline LightRefBase() : mCount(0) {}
inline void incStrong(const void* id) const {
android_atomic_inc(&mCount);
}
inline void decStrong(const void* id) const {
if (android_atomic_dec(&mCount) == 1) {
delete static_cast<const T*>(this);
}
}
//! DEBUGGING ONLY: Get current strong ref count.
inline int32_t getStrongCount() const {return mCount;}
protected:
inline ~LightRefBase() { }
private:
mutable volatile int32_t mCount;
};

android_atomic_inc()^footnote
android_atomic_dec()^footnote2
计数器,递减到0的时候就delete掉对象。

重量级引用计数类 RefBase

不同于LightRefBase的是,RefBase内部并没有使用一个变量来维护引用计数,而是通过一个weakref_impl *类型的成员来维护引用计数,并且同时提供了强引用计数和弱引用计数。weakref_impl继承于RefBase::weakref_type。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class RefBase
{
public:
void incStrong(const void* id) const;
void decStrong(const void* id) const;
void forceIncStrong(const void* id) const;
class weakref_type
{
public:
RefBase* refBase() const;
void incWeak(const void* id);
void decWeak(const void* id);
bool attemptIncStrong(const void* id);
//! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
bool attemptIncWeak(const void* id);
};
weakref_type* createWeak(const void* id) const;
weakref_type* getWeakRefs() const;
protected:
RefBase();
virtual ~RefBase();
//! Flags for extendObjectLifetime()
enum {
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_FOREVER = 0x0003
};
void extendObjectLifetime(int32_t mode);
//! Flags for onIncStrongAttempted()
enum {
FIRST_INC_STRONG = 0x0001
};
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
virtual void onLastWeakRef(const void* id);
private:
friend class weakref_type;
class weakref_impl;
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
weakref_impl* const mRefs;
};

RefBase类的成员变量mRefs的类型为weakref_impl指针,在去除debug代码后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatile int32_t mStrong;
volatile int32_t mWeak;
RefBase* const mBase;
volatile int32_t mFlags;
Destroyer* mDestroyer;
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
, mDestroyer(0)
{
}
void addStrongRef(const void* /*id*/) { }
void removeStrongRef(const void* /*id*/) { }
void addWeakRef(const void* /*id*/) { }
void removeWeakRef(const void* /*id*/) { }
void printRefs() const { }
void trackMe(bool, bool) { }
};

类图:
RefBase

强指针数类 sp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
template <typename T>
class sp
{
public:
typedef typename RefBase::weakref_type weakref_type;
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
template<typename U> sp(U* other);
template<typename U> sp(const sp<U>& other);
~sp();
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);
void clear();
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;
// Optimization for wp::promote().
sp(T* p, weakref_type* refs);
T* m_ptr;
};

使用轻量级引用计数:
重点只关注成员变量m_ptr、构造函数和析构函数;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//构造函数里面都是初始化了成员变量,并且调用变量的incStrong函数来增加对象的引用计数。
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
{
if (other) other->incStrong(this);
}
template<typename T>
sp<T>::sp(const sp<T>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) m_ptr->incStrong(this);
}
//析构函数调用m_ptr的成员函数decStrong来减少对象的引用计数值
template<typename T>
sp<T>::~sp()
{
if (m_ptr) m_ptr->decStrong(this);
}

继承轻量级引用计数使用例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class LightClass : public LightRefBase<LightClass>
{
public:
LightClass() {}
virtual ~LightClass() {}
};
int main(int argc, char** argv)
{
LightClass* pLightClass = new LightClass();
sp<LightClass> lpOut = pLightClass;
{
sp<LightClass> lpInner = lpOut;
}
return 0;
}

使用重量级引用计数:
强指针:
使用重量级引用计数一定是继承于RefBase类,在构造函数传进来的就是RefBase类,调用的是RefBase类的incStrong函数。
在RefBase类的incStrong函数中,主要做了三件事情:一是增加弱引用计数;二是增加强引用计数;三是如果发现是首次调用这个对象的incStrong函数,就会调用一个这个对象的onFirstRef函数,让对象有机会在对象被首次引用时做一些处理逻辑。
总体来说强指针类sp在其构造函数里面所做的事情就是分别为目标对象的强引用计数和弱引和计数增加了1。
在析构函数里,如果发现减1前,此对象的强引用计数为1,就说明从此以后,就再没有地方引用这个目标对象了,这时候,就要看看是否要delete这个目标对象了,在强引用计数为0的情况下,如果对象的标志位OBJECT_LIFETIME_WEAK被设置了,就说明这个对象的生命周期是受弱引用计数所控制的,因此,这时候就不能delete对象,要等到弱引用计数也为0的情况下,才能delete这个对象。
总结:
A:如果对象的标志位被设置为0,那么只要发现对象的强引用计数值为0,那就会自动delete掉这个对象;
B:如果对象的标志位被设置为OBJECT_LIFETIME_WEAK,那么只有当对象的强引用计数和弱引用计数都为0的时候,才会自动delete掉这个对象;
C:如果对象的标志位被设置为OBJECT_LIFETIME_FOREVER,那么对象就永远不会自动被delete掉,谁new出来的对象谁来delete掉。

弱指针数类 wp

弱指针所使用的引用计数类与强指针一样,都是RefBase类。
弱指针的最大特点是它不能直接操作目标对象,因为弱指针类没有重载*和->操作符号,而强指针重载了这两个操作符号。如果我们要操作目标对象,就要把弱指针升级为强指针。

1
2
3
4
5
template<typename T>
sp<T> wp<T>::promote() const
{
return sp<T>(m_ptr, m_refs);
}

强弱指针用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <stdio.h>
#include <utils/RefBase.h>
#define INITIAL_STRONG_VALUE (1<<28)
using namespace android;
class WeightClass : public RefBase
{
public:
void printRefCount()
{
int32_t strong = getStrongCount();
weakref_type* ref = getWeakRefs();
printf("-----------------------\n");
printf("Strong Ref Count: %d.\n", (strong == INITIAL_STRONG_VALUE ? 0 : strong));
printf("Weak Ref Count: %d.\n", ref->getWeakCount());
printf("-----------------------\n");
}
};
class StrongClass : public WeightClass
{
public:
StrongClass()
{
printf("Construct StrongClass Object.\n");
}
virtual ~StrongClass()
{
printf("Destory StrongClass Object.\n");
}
};
class WeakClass : public WeightClass
{
public:
WeakClass()
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
printf("Construct WeakClass Object.\n");
}
virtual ~WeakClass()
{
printf("Destory WeakClass Object.\n");
}
};
class ForeverClass : public WeightClass
{
public:
ForeverClass()
{
extendObjectLifetime(OBJECT_LIFETIME_FOREVER);
printf("Construct ForeverClass Object.\n");
}
virtual ~ForeverClass()
{
printf("Destory ForeverClass Object.\n");
}
};
void TestStrongClass(StrongClass* pStrongClass)
{
wp<StrongClass> wpOut = pStrongClass;
pStrongClass->printRefCount();
{
sp<StrongClass> spInner = pStrongClass;
pStrongClass->printRefCount();
}
sp<StrongClass> spOut = wpOut.promote();
printf("spOut: %p.\n", spOut.get());
}
void TestWeakClass(WeakClass* pWeakClass)
{
wp<WeakClass> wpOut = pWeakClass;
pWeakClass->printRefCount();
{
sp<WeakClass> spInner = pWeakClass;
pWeakClass->printRefCount();
}
pWeakClass->printRefCount();
sp<WeakClass> spOut = wpOut.promote();
printf("spOut: %p.\n", spOut.get());
}
void TestForeverClass(ForeverClass* pForeverClass)
{
wp<ForeverClass> wpOut = pForeverClass;
pForeverClass->printRefCount();
{
sp<ForeverClass> spInner = pForeverClass;
pForeverClass->printRefCount();
}
}
int main(int argc, char** argv)
{
printf("Test Strong Class: \n");
StrongClass* pStrongClass = new StrongClass();
TestStrongClass(pStrongClass);
printf("\nTest Weak Class: \n");
WeakClass* pWeakClass = new WeakClass();
TestWeakClass(pWeakClass);
printf("\nTest Froever Class: \n");
ForeverClass* pForeverClass = new ForeverClass();
TestForeverClass(pForeverClass);
pForeverClass->printRefCount();
delete pForeverClass;
return 0;
}