C/C++项目中常见的指针问题可以归纳为:
1. 指针没有初始化
对指针进行初始化是程序员必须养成的良好习惯,也是指针问题中最容易解决和控制的一个(其实不仅是指针的初始化,新分配的内存块在进行操作前都应视实际情况进行初始化)
2. new 了对象后没有及时delete
3.野指针
智能指针就是用来解决这三个问题的
那么智能指针应该如何设计呢
SmartPointer应该是一个模板类
template <typename T>
class SmartPointer
{
inline SmartPointer():m_ptr(0) {}
private:
T * m_ptr;
}
智能指针怎么知道该什么时候释放掉一个内存对象呢,这就需要引用计数来实现
那引用计数应该由谁管理,智能指针拥有的话就会导致如下问题:
如果两个智能指针同时指向同一个对象,那么其中一个智能指针的引用计数为0是就会释放掉这个对象,另一个智能指针还在使用这个对象的话,就会引发致命的问题
解决的唯一方法就是 引用计数由Object拥有
我们可以让所有的对象都继承于这个拥有计数功能的父类,如下方这个例子
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;
};
incStrong和decStrong分别用于增加和减少引用计数值,那这两个函数在什么情况下被调用呢?既然是引用计数,当然是在被引用时,这个工作有SmartPointer来完成
SmartPointer<TYPE> smartP = new object;
当一个智能指针引用了object时,其父类的incStrong就会被调用。所有SmartPointer必须重载它的“=“运算符。
template<typename T>
SmartPointer <T> & SmartPointer<T>::operator = (T *other) {
if(other != NULL) {
m_ptr = other;//指向内存对象
other->incStrong();//增加引用计数值
}
return *this;
}
当SmartPointer析构时,也应该及时调用decStrong来释放引用;
在Android中其实存在sp(强指针)和wp(弱指针)之分
sp的定义在StrongPointer.h (rs\cpp\util) ,wp的定义在RefBase.h (rs\cpp\util)
template <typename T>
class sp
{
public:
inline sp() : m_ptr(0) { }
sp(T* other); // NOLINT, implicit
sp(const sp<T>& other);
template<typename U> sp(U* other); // NOLINT, implicit
template<typename U> sp(const sp<U>& other); // NOLINT, implicit
~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;
};
sp模板类的实现跟StrongPointer比较相似。也比较好理解
为什么又提出了个弱指针,其使用场景又是什么呢;
考虑如下场景:父对象parent指向子对象child,然后子对象又指向了父对象,这就存在循坏引用的情况
struct Dad
{
Child * myChild;
};
struct Child
{
Dad * myDad;
}
如果没有智能指针,这样的情况不会导致任何问题,若有智能指针,就会出现内存死锁
解决这个问题的有效方法就是使用弱指针来实现
Dad使用强指针来引用Child,而Child使用弱引用来指向Dad。双方规定档强引用计数为0时,不论若引用计数是否为0,都可以delete自己(在Android中这个规则是可以改变的),这样一方得到了释放,就可以成功避免内存死锁,但这样会导致Child指向的Dad对象不存在的话,引出野指针问题,可以用以下方式避免:
弱指针必须先升级为强指针,才能访问它所指向的目标对象
弱指针主要就是解决循坏引用的问题
template <typename T>
class wp
{
public:
typedef typename RefBase::weakref_type weakref_type;
inline wp() : m_ptr(0) { }
explicit wp(T* other);
wp(const wp<T>& other);
explicit wp(const sp<T>& other);
template<typename U> explicit wp(U* other);
template<typename U> explicit wp(const sp<U>& other);
template<typename U> explicit wp(const wp<U>& other);
~wp();
// Assignment
wp& operator = (T* other);
wp& operator = (const wp<T>& other);
wp& operator = (const sp<T>& other);
template<typename U> wp& operator = (U* other);
template<typename U> wp& operator = (const wp<U>& other);
template<typename U> wp& operator = (const sp<U>& other);
void set_object_and_refs(T* other, weakref_type* refs);
// promotion to sp
sp<T> promote() const;//升级为强指针
// Reset
void clear();
// Accessors
inline weakref_type* get_refs() const { return m_refs; }
inline T* unsafe_get() const { return m_ptr; }
// Operators
COMPARE_WEAK(==)
COMPARE_WEAK(!=)
COMPARE_WEAK(>)
COMPARE_WEAK(<)
COMPARE_WEAK(<=)
COMPARE_WEAK(>=)
inline bool operator == (const wp<T>& o) const {
return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
}
template<typename U>
inline bool operator == (const wp<U>& o) const {
return m_ptr == o.m_ptr;
}
inline bool operator > (const wp<T>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
}
template<typename U>
inline bool operator > (const wp<U>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
}
inline bool operator < (const wp<T>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
}
template<typename U>
inline bool operator < (const wp<U>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
}
inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
T* m_ptr;
weakref_type* m_refs;//另外一个指向m_refs的指针
};
wp的构造函数
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
createWeak是RefBase的方法,weakref_type是RefBase的一个内部嵌套类
class weakref_type
{
public:
RefBase* refBase() const;
void incWeak(const void* id);
void decWeak(const void* id);
// acquires a strong reference if there is already one.
bool attemptIncStrong(const void* id);
// acquires a weak reference if there is already one.
// This is not always safe. see ProcessState.cpp and BpBinder.cpp
// for proper use.
bool attemptIncWeak(const void* id);
//! DEBUGGING ONLY: Get current weak ref count.
int32_t getWeakCount() const;
//! DEBUGGING ONLY: Print references held on object.
void printRefs() const;
//! DEBUGGING ONLY: Enable tracking for this object.
// enable -- enable/disable tracking
// retain -- when tracking is enable, if true, then we save a stack trace
// for each reference and dereference; when retain == false, we
// match up references and dereferences and keep only the
// outstanding ones.
void trackMe(bool enable, bool retain);
};
RefBase还有一个weakref_impl;其实现在system//core/libutils/RefBase.cpp中
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
std::atomic<int32_t> mStrong;//强引用计数值
std::atomic<int32_t> mWeak;//弱引用计数值
RefBase* const mBase;
std::atomic<int32_t> mFlags;
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);//增加弱引用计数
return mRefs;//直接返回weakref_type对象
}
mRefs也就是weakref_impl类型的成员变量,这个函数增加了弱引用计数,然后返回这个mRefs。
和LightRefBase不同,RefBase不是直接使用int变量来保存引用计数,而是采用了weakref_type类型的计数器。因为RefBase需要处理多种计数类型。wp中的m_refs和RefBase中的mRefs都指向了计数器。wp通过createWeak获得计数器的地址,而计数器本身是有RefBase在构造时创建的
RefBase::RefBase()
: mRefs(new weakref_impl(this))
{
}
整个wp机制很复杂,但中心都是围绕着新的计数器weakref_impl而已