Android架构分析之Android智能指针(一)

作者:刘昊昱

博客:http://blog.csdn.net/liuhaoyutz

Android版本:4.4.2

在C++语言中,指针操作是最容易问题的地方,常见的指针操作错误有以下几种:

1、      定义一个指针,但没有对其进行初始化。这种情况下,指针会指向一个随机地址,此时使用该指针,将出现不可预知的错误。一般定义一个指针时,应该同时对该指针进行初始化。

2、      new了一个对象后,忘记delete该对象。这种情况会造成内存泄漏,时间久了,重复多次,可能造成系统宕机。

3、      野指针。例如,我们new了一个对象A,并用指针p1指向A,使用结束后,我们delete了对象A,此时,p1还是指向A原来的地址,但是A被delete后,该地址是非法地址。这样的p1就是野指针。再举一个例子,p1和p2两个指针都指向A,我们通过p1指针delete了A之后,将p1设置为NULL,但p2仍然指向A原来地址,此时,p2就是野指针。

为了避免上述C++指针使用错误,Android为我们提供了智能指针,定义在frameworks/rs/cpp/util目录下的RefBase.h和StrongPointer.h文件中。

Android智能指针是一个模板类,又分为强指针sp和弱指针wp。强指针sp定义如下:

 62template<typename T>
 63class sp
 64{
 65public:
 66    inline sp() : m_ptr(0) { }
 67
 68    sp(T* other);
 69    sp(const sp<T>& other);
 70    template<typename U> sp(U* other);
 71    template<typename U> sp(constsp<U>& other);
 72
 73    ~sp();
 74
 75    // Assignment
 76
 77    sp& operator = (T* other);
 78    sp& operator = (const sp<T>&other);
 79
 80    template<typename U> sp& operator= (const sp<U>& other);
 81    template<typename U> sp& operator= (U* other);
 82
 83    //! Special optimization for use byProcessState (and nobody else).
 84    void force_set(T* other);
 85
 86    // Reset
 87
 88    void clear();
 89
 90    // Accessors
 91
 92    inline T&      operator* ()const  { return *m_ptr; }
 93    inline T*      operator-> () const {return m_ptr;  }
 94    inline T*      get() const         { return m_ptr; }
 95
 96    // Operators
 97
 98    COMPARE(==)
 99    COMPARE(!=)
100    COMPARE(>)
101    COMPARE(<)
102    COMPARE(<=)
103    COMPARE(>=)
104
105private:
106    template<typename Y>friend class sp;
107    template<typename Y>friend class wp;
108    void set_pointer(T* ptr);
109    T* m_ptr;
110};

66-71行,定义了5种sp构造函数。

73行,定义了sp的析构函数。

77-81行,定义了4种“=”运算符的重载函数。

92-103行,对其它8种运算符进行重载。每个COMPARE宏对应该运算符的6个重载函数。

109行,定义T类型指针变量m_ptr。这个指针变量m_prt即是sp类的核心。

我们可以这样理解sp类:

1、sp类的对象实例用来替代我们原来所用的指针。

2、sp类是对指针的封装。sp.m_prt即我们原来所用的指针。

3、通过使用sp类的对象代替指针,可以避免出现原来使用指针时常见的错误。

为什么说使用sp类的对象代替指针,就可以避免原来使用指针时常见的错误呢?

首先来看使用指针的第一种常见错误,即定义指针时没有进行初始化。

使用sp类对象代替指针后,创建sp类对象时会调用到sp类构造函数,在构造函数中,会对sp.m_ptr进行初始化,例如:

66    inline sp() : m_ptr(0) { }

默认构造函数将sp.m_ptr初始化为0。

再比如:

120template<typename T>
121sp<T>::sp(T* other)
122: m_ptr(other)
123  {
124    if (other)other->incStrong(this);
125  }

该构造函数将sp.m_ptr初始化为通过参数传递进来的other。

除了构造函数,对sp对象进行初始化还可能通过赋值运算符,例如:

sp<Object> = new Object

这种情况下,就用到了sp的“=”重载运算符:

162template<typename T>
163sp<T>& sp<T>::operator = (T* other)
164{
165    if (other) other->incStrong(this);
166    if (m_ptr)m_ptr->decStrong(this);
167    m_ptr = other;
168    return *this;
169}

可以看到,在“=”重载运算符中,167行,将参数传递进来的other赋值给sp.m_ptr。

这样通过在构造函数和重载赋值运算符中完成对sp.m_ptr的初始化,即避免了使用指针的第一种常见错误(定义指针时忘记初始化)。

使用指针的第二种常见错误(new一个对象后忘记delete)和第三种常见错误(野指针)可以通过给被指针指向的对象加一个引用计数器来解决。我们可以想象一下,如果被指针指向的对象有一个引用计数器,即当有一个指针指向该对象时,该对象引用计数器为1,有两个指针指向该对象时,该对象引用计数器为2,依次类推。反之,当一个指针不再指向该对象时,该对象引用计数器的值减1,当对象引用计数器的值为0时,该对象需要被delete。

怎样给对象设置一个引用计数器呢?Android智能指针的做法是让该对象对应的类继承LightRefBase模板类,该类定义在frameworks/rs/cpp/util/RefBase.h文件中:

163template <class T>
164class LightRefBase
165{
166public:
167    inline LightRefBase() :mCount(0) { }
168    inline voidincStrong(__attribute__((unused)) const void* id) const {
169       __sync_fetch_and_add(&mCount, 1);
170    }
171    inline voiddecStrong(__attribute__((unused)) const void* id) const {
172        if(__sync_fetch_and_sub(&mCount, 1) == 1) {
173            deletestatic_cast<const T*>(this);
174        }
175    }
176    //! DEBUGGING ONLY: Getcurrent strong ref count.
177    inline int32_tgetStrongCount() const {
178        return mCount;
179    }
180
181    typedefLightRefBase<T> basetype;
182
183protected:
184    inline ~LightRefBase() { }
185
186private:
187    friend classReferenceMover;
188    inline static void moveReferences(void*,void const*, size_t,
189            constReferenceConverterBase&) { }
190
191private:
192    mutable volatile int32_tmCount;
193};

192行,定义了一个整数mCount,这就是所谓的引用计数器。

167行,LightRefBase的构造函数将引用计数器mCount初始化为0。

168-170行,定义了incStrong函数,用于将引用计数器mCount的值加1。

171-175行,定义了decStrong函数,用于将引用计数器mCount的值减1,需要注意的是,如果减1之前,mCount的值为1,说明对本对象最后的引用也解除了,则会delete本对象,这样就避免了我们所说的new一个对象,忘记delete。

知道了LightRefBase的定义,我们再回过头来看sp类,就能理解智能指针是怎样工作的了。

sp的构造函数如下:

120template<typename T>
121sp<T>::sp(T* other)
122: m_ptr(other)
123  {
124    if (other)other->incStrong(this);
125  }

sp的重载赋值运算符如下:

162template<typename T>
163sp<T>& sp<T>::operator = (T* other)
164{
165    if (other)other->incStrong(this);
166    if (m_ptr)m_ptr->decStrong(this);
167    m_ptr = other;
168    return *this;
169}

类T继承LightRefBase,可以看到,通过构造函数或赋值运算让sp对象指向T对象,除了将other赋值给sp.m_ptr外,因为这两种情况都属于增加一个对象引用计数,所以还会调用other->incStrong(this)。特别需要注意的是,在赋值运算中,如果m_ptr之前指向其它值,则需要先调用m_ptr->decStrong(this),即对应对象引用计数减1,然后再将other赋值给sp.mptr。

sp的析构函数如下:

147template<typename T>
148sp<T>::~sp()
149{
150    if (m_ptr)m_ptr->decStrong(this);
151}

可见,当智能指针sp析构时,会调用m_ptr->decStrong(this)让对应对象的引用计数器减1。

Android架构分析之Android智能指针(一)

时间: 2024-07-29 08:21:29

Android架构分析之Android智能指针(一)的相关文章

Android架构分析之Android智能指针(二)

作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本:4.4.2 在上一篇文章中,我们分析了Android智能指针中的强指针sp,本文我们来分析弱指针wp.为什么需要弱指针wp呢?我们来考虑下面一种场景:有两个类CParent和CChild,CParent类中有一个智能指针指向CChild对象,CChild类中有一个智能指针指向CParent对象 class CParent :public LightRefBase<CParent> { --

Android架构分析之Android消息处理机制(二)

作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本:4.4.2 在上一篇文章中我们看了一个使用Handler处理Message消息的例子,本文我们来分析一下其背后隐藏的Android消息处理机制. 我们可能比较熟悉Windows操作系统的消息处理模型: while(GetMessage(&msg,NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } 1.消息

Android架构分析之Android消息处理机制(三)

作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本:4.4.2 本文我们来分析AndroidUI线程即主线程是怎样实现对消息的处理的. UI线程的实现类定义在frameworks/base/core/java/android/app/ActivityThread.java文件中.我们来看Android对ActivityThread类的说明 : 130/** 131 * This manages the execution of the main

Android架构分析之Handler分析(一)

作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 本文介绍了一个使用Handler的Android应用程序,通过该程序,我们可以了解Handler的基本用法.该程序运行效果如下: 点击Button1按钮后,运行效果如下: 点击Button2按钮后,运行效果如下: 下面我们来看这个程序代码. 主程序TestHandlerActivity.java内容如下: package com.haoyu.testHandler; import android.app.Acti

Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6786239 Android 系统的运行时库层代码是用C++来编写的,用C++来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃.不过系统为 我们提供了智能指针,避免出现上述问题,本文将系统地分析Android系统智能指针(轻量级指针.强指针和弱指针)的实现原理. 在使用C++来编写代码的过程中,指针使用不当造成

Android系统篇之----Android中的智能指针

一.前言 今天我们开启Android系统篇的文章了,其实一直想弄,只是之前一直没有太多深入的了解,最近又把这块拿出来好好看了一下,所以想从新梳理一下,来看看Android中的这块知识,首先我们今天来看一下:Android中的智能指针的概念,为什么说先看一下智能指针这个知识呢?因为我们在看Android源码的时候,会发现几乎好多地方都用到了这个东东,所以我们在介绍后面的知识点,先来看看这个吧. 二.问题 那么Android中的智能指针是个什么东西呢?我们知道Android用的Java语言开发的,J

Android基础入门教程——1.1 背景相关与系统架构分析

Android基础入门教程--1.1 背景相关与系统架构分析 1.Android背景与当前的状况 Android系统是由Andy Rubin创建的,后来被Google收购了:最早的版本是:Android 1.1版本 而现在最新的版本是今年5.28,Google I/O大会上推出的Android M,有趣的是Android系统的命名都是以点心来命名的,下述表是15个Android版本名称,对应API号以及发布时间! 系统版本名称 API版本号 发布时间 Android 1.5:Cupcake:纸杯

Chromium和WebKit的智能指针实现原理分析

C++不像Java一样,由虚拟机负责对象分配和释放.也就是说,开发人员使用C++编写代码时,要自己负责对象分配和释放.WebKit和Chromium都是使用C++开发的,因此它们也面临上述问题.在解决对象释放问题时,要做到在对象不需要时自动释放,因为手动释放会带来忘记释放或者释放后又继续使用的隐患.智能指针是实现对象自动释放的有效技术手段.本文就分析Chromium和WebKit的智能指针的实现. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! 在现实中,

Android核心分析28篇,强烈推荐android初学者,android进阶者看看这个系列教程

Android核心分析 之一分析方法论探讨之设计意图 http://www.apkbus.com/android-24212-1-1.html Android核心分析 之二方法论探讨之概念空间篇 http://www.apkbus.com/android-24213-1-1.html Android是什么 之三手机之硬件形态 http://www.apkbus.com/android-24215-1-2.html Android核心分析之四手机的软件形态 http://www.apkbus.co