很久没有碰C++了,用了两周时间复习了一下,感觉知识应该时常巩固,不然很容易忘掉。
智能指针是一种能够自动维护对象引用计数的技术,用来管理C++对象的释放。因为C++不像Java有自动回收机制,C++需要程序员手动的来释放堆资源(通过New 出来的对象-----指针)。如果程序一直都不释放内存,那么长期运行,必定造成内存吃紧。如果我们手动来释放资源,我们又将面临另一个难题,当两个对象都指向同一个内存地址(同一指针对象),当其中的一个对象A删除了所指向内存地址的数据,而此时,对象B再来访问内存地址里的数据,必定会出现混乱(因为数据已经被删除了),这里我们想到,如果使用Java来测试,必然会抛出NullPointerException。
Android的智能指针有三种,轻量级指针(LightRefBase通过简单的引用计数来维护对象的生命周期),强引用指针(使用了强引用计数技术),弱引用指针(弱引用计数技术)。
一 。 轻量级指针
我们来看Android 系统源代码 system\core\include\utils\RefBase(Android 版本4.4以后的路径)
Read the fucking source code! ----Linus
template
<
class
T>
class
LightRefBase
{
public
:
inline
LightRefBase() : mCount(0) { }
inline
void
incStrong(__attribute__((unused))
const
void
* id)
const
{
android_atomic_inc(&mCount); //mCount+1 内部使用了线程互斥机制
}
inline
void
decStrong(__attribute__((unused))
const
void
* id)
const
{
if
(android_atomic_dec(&mCount) == 1) {
//mCount-1 线程互斥机制,返回在减1前的值
delete
static_cast
<
const
T*>(
this
); //如果没有指针指向这个地址,删除
/*
static_cast 用于向上转型 将this 转换成 T*
*/
}
}
//! 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
renameRefs(size_t n,
const
ReferenceRenamer& renamer) { }
inline
static
void
renameRefId(T* ref,
const
void
* old_id,
const
void
* new_id) { }
private
:
/*
当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。
因为该变量可能在多线程中访问(我们的操作系统中把它称为临界资源),所以要求每次都要去重新读取,当然单一使用这个修饰符是不足
以实现线程同步,所以还是要配合mutex来实现。
mutable 是用来消除变量的const 修饰,为撒要用这个来修饰呢?
原因是:在函数
inline
void
incStrong() const{...},函数被const修饰,是不允许在函数内存修改类的任何属性的,但是在函数的实现中又对mCount进行了加1操作,所以冲突了,故用mutable来去掉const的修饰(PS:既然要修改mCount的值,为什么Google工程师还要用const来修饰函数呢?)
*
/
mutable
volatile
int32_t mCount;
};
分析:
通过代码我们可以看到,轻引用只是维护了一个int变量mCount (int32_t是一个结构体,是通过不同系统来定义一个32位的整数,因为Int在不同的硬件系统中所占用的长度不一定是32位),而该类是一个模板类(联想到Java的泛型类),在使用该类时,需要指明该类中的T到底是什么类型。该类主要是实现了一个计数器的功能,如果需要实现轻量级引用计数功能,还需要其他类来辅助。sp这个类实现了轻引用计数和强引用计数功能,这里我们暂时来分析轻引用计数的实现。
SP 实现在\system\core\include\utils\StrongPoint
//注解①
#define
COMPARE
(_op_) \
inline
bool
operator
_op_ (
const
sp<T>& o)
const
{ \
return
m_ptr _op_ o.m_ptr; \
} \
inline
bool
operator
_op_ (
const
T* o)
const
{ \
return
m_ptr _op_ o; \
} \
template
<
typename
U> \
inline
bool
operator
_op_ (
const
sp<U>& o)
const
{ \
return
m_ptr _op_ o.m_ptr; \
} \
template
<
typename
U> \
inline
bool
operator
_op_ (
const
U* o)
const
{ \
return
m_ptr _op_ o; \
} \
inline
bool
operator
_op_ (
const
wp<T>& o)
const
{ \
return
m_ptr _op_ o.m_ptr; \
} \
template
<
typename
U> \
inline
bool
operator
_op_ (
const
wp<U>& o)
const
{ \
return
m_ptr _op_ o.m_ptr; \
}
// ---------------------------------------------------------------------------
template
<
typename
T
>
class
sp
{
public
:
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();
// 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;
};
#undef
COMPARE
// ---------------------------------------------------------------------------
// No user serviceable parts below here.
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
);
}
template
<
typename
T
>
template
<
typename
U
>
sp
<
T
>::sp(
U
*
other
)
: m_ptr(
other
) {
if
(
other
)
((
T
*)
other
)->incStrong(
this
);
}
template
<
typename
T
>
template
<
typename
U
>
sp
<
T
>::sp(
const
sp
<
U
>&
other
)
: m_ptr(
other
.m_ptr) {
if
(m_ptr)
m_ptr->incStrong(
this
);
}
template
<
typename
T
>
sp
<
T
>::~sp() {
if
(m_ptr)
m_ptr->decStrong(
this
);
}
template
<
typename
T
>
sp
<
T
>&
sp
<
T
>::operator =(
const
sp
<
T
>&
other
) {
T
* otherPtr(
other
.m_ptr);
if
(otherPtr)
otherPtr->incStrong(
this
);
if
(m_ptr)
m_ptr->decStrong(
this
);
m_ptr = otherPtr;
return
*
this
;
}
template
<
typename
T
>
sp
<
T
>&
sp
<
T
>::operator =(
T
*
other
) {
if
(
other
)
other
->incStrong(
this
);
if
(m_ptr)
m_ptr->decStrong(
this
);
m_ptr =
other
;
return
*
this
;
}
template
<
typename
T
>
template
<
typename
U
>
sp
<
T
>&
sp
<
T
>::
operator
=(
const
sp
<
U
>& other) {
T* otherPtr(other.m_ptr);
if
(otherPtr)
otherPtr->incStrong(
this
);
if
(m_ptr)
m_ptr->decStrong(
this
);
m_ptr = otherPtr;
return
*
this
;
}
template
<
typename
T
>
template
<
typename
U
>
sp
<
T
>&
sp
<
T
>::operator =(
U
*
other
) {
if
(
other
)
((
T
*)
other
)->incStrong(
this
);
if
(m_ptr)
m_ptr->decStrong(
this
);
m_ptr =
other
;
return
*
this
;
}
template
<
typename
T
>
void
sp
<
T
>::force_set(
T
* other) {
other->forceIncStrong(
this
);
m_ptr = other;
}
template
<
typename
T
>
void
sp
<
T
>::clear() {
if
(m_ptr) {
m_ptr->decStrong(
this
);
m_ptr = 0;
}
}
template
<
typename
T
>
void
sp
<
T
>::set_pointer(
T
* ptr) {
m_ptr = ptr;
}
分析:
注解① : 这里是一系列的宏函数定义,主要是实现一系列的运算符重载(除了 = ) 这里的 = 有特殊的含义(两者间进行辅赋值的时候调用),这里帮大家复习一下:
假如A是一个类; A* a = new A(); A* b = a; //调用拷贝构造函数 A* c ; c = a; // =运算符重载
注解② :这里包含4个构造函数(两个普通的构造函数,两个拷贝构造函数),这里我们来分析一组普通的构造函数
sp(
T* other); 和
template
<
typename
U
> sp(
U
* other);两者的区别在于后者是一个模板函数,由于两者都是
构造函数,那必然有个优先级,这里当然是前一个构造函数运行优先级高,因其确定。而为啥要提供一个模板构造函数来重载前一个构造函数呢,原因是我们可能传过来的可能不是T这个类型,而是另一种类型U(他的兄弟类,我自己的叫法)
注解
③ : = 运算符的重载,为什么要专门进行 = 运算符的重载呢?因为
A* a = new A();
A* c ; c = a; 这时就有俩个指针同时指向new A()这个地址,引用计数为2,所以我们将在构造函数中将引用计数mCount设置为1,再进行拷贝构造函数,或者调用
c = a;时对引用计数进行加1 ,什么时候减1呢?当然是在析构函数中
注解
④ : 运算符重载,让使用这个类如同使用指针一样
注解
⑤
: 调用宏函数来直接替换
注解⑥ : T* 实际指向一个实际类型的变量
该类的主要作用是:
在调用该类的构造函数的时候,会传过来一个实际对象,此时,就会把该实际对象赋给m_ptr这个变量存起来,如果以后再调用该类对象的拷贝构造函数,或者=运算符重载函数时,那么实际调用的是m_ptr的函数来进行引用加1,这就是我们在使用轻量级计数时要继承LightRefBase这个类,因为我们需要调用它的方法,如果我们不继承,那么就无法调用到操作引用计数器的函数。
说了这么多,来教大家如何使用:
使用时有两个前提:
1)需要引用计数的类继承LightRefBase
2)为该类提供一个virtual 的析构函数
#define
DEBUG
1
#define
PRINT_DEBUG
() \
if
(
DEBUG
) \
cout<<
"current line = "
<<
__LINE__
<<endl
//这个宏函数是我写来调试代码执行到哪里
class
NN
:
public
LightRefBase
<
NN
>{ //
LightRefBase
<
NN
> 记得添加模板,因为这是一个模板类
public
:
NN(){
PRINT_DEBUG
();}
virtual
~NN(){
PRINT_DEBUG
();}
};
int
main(
int
argc
,
char
**
argv
){
/*
sp<NN>* nn = new sp<NN>(new NN());
cout<< nn->get()->getStrongCount();
这样做也是可以的
*/
NN
* n =
new
NN
();
//引用计数初始化为0
sp
<
NN
> nn = n; //引用计数加1
cout<<
"Light Ref count = "
<<n->getStrongCount()<<endl;// 输出1
{
sp
<
NN
> inner = nn;
//引用计数加1
sp
<
NN
> inner2 = nn;
//引用计数加1
cout<<
"Light Ref count = "
<<n->getStrongCount()<<endl;
//输出3
}
//因为inner 和 inner2只在{}有效,出了“}”就会被释放掉(这里是对象不是指针,不然是不会自动释放的),所以减2
cout<<
"Light Ref count = "
<<n->getStrongCount()<<endl; //输出1
getchar();
return
0;
}
运行结果:
结语:
来至绵阳师范学院 (招生代码: 5123, 绵阳师范学院欢迎您)信息工程学院13级4班李超(学习andorid 一年半,有意招聘请发送邮件至:857713709@qq.com)。
下一节将分析强引用和弱引用的实现机制 3Q :)
时间:2016/4/15