智能指针
1.简介
1.指针问题的常见来源:
- 指针没有初始化
- new了对象后没有及时delete
- 野指针
通过delete释放了对象,但没有将指针置空。
2.如何设计一个智能指针
考虑的因素:
- 初始化;
- 实现new和delete的配套;
具体的设计实现:
我们将智能指针称为SmartPointer。
- SmartPointer是一个类
首先想到的是,SmartPointer要能记录内存对象Object的地址,它的内部应该有一个变量指向Object,所以SmartPointer是一个类。
class SmartPointer{
private:
void* m_ptr;//指向Object对象
}
- SmartPointer是一个模板类
智能指针并不是针对某种特定类型的对象而设计的,因而一定是模板类。
template <typename T> class SmartPointer{
private:
T* m_ptr;//指向Object对象
}
- SmartPointer的构造函数
智能指针需要考虑的一个问题就是初始化,所以智能指针的构造函数应将m_ptr置空。
template <typename T> class SmartPointer{
inline SmartPointer() : m_ptr(0) {}
private:
T *m_ptr;//指向Object
}
- 引用计数
智能指针还需考虑的一个问题是什么时候释放一个内存对象?可以考虑通过引用计数来统计对象使用的次数,如果对象的引用次数为0了,则可以释放该对象了。引用计数该由谁来管理呢?
如果由智能指针自己来维护引用计数的话,将会出现引用计数不一致的情况,导致致命错误。
如果由引用对象Object自己维护计数器,则可以解决此问题。我们可以定义一个统一的具备计数功能的父类Object。
template <class T> class LightRefBase{
public:
inline LightRefBase() : mCount(0) {}
// 增加引用计数
inline void incStrong() const {
android_atomic_inc(&mCount);
}
// 减小引用计数
inline void decStrong() const {
if(android_atomic_dec(&mCount) == 1){
delete static_cast<const T*>(this);//删除内存对象
}
}
protected:
inline ~LightBaseRef() {}
private:
muteable volatile int32_t mCount;//引用计数值
}
为此智能指针SmartPointer需要重载“=”运算符,其定义也需要修改:
template <typename T> class SmartPointer{
inline SmartPointer() : m_ptr(0) {}
~SmartPointer();
SmartPointer& operator = (T* other);//重载运算符
private:
T* m_ptr;
}
template <typename T> SmartPointer<T>& SmartPointer<T>::operator = (T *other){
if(other != null){
other->incStrong();//主动增加计数值
}
if(m_ptr){
m_ptr->decStrong();// 避免重复赋值的情况
}
m_ptr = other;//指向内存对象Object
return *this;
}
template <typename T> SmartPointer<T>::~SmartPointer(){
if(m_ptr){
m_ptr->decStrong();
}
}
2.强指针sp
sp是StrongPointer的简写,StrongPointer定义在frameworks/native/include/utils/StrongPointer.h
sp类的定义如下:
template <typename T>
class sp
{
public:
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
.......其他构造函数
~sp();// 析构函数
//重载运算符
sp& operator = (T* other);
sp& operator = (const sp<T>& other);
.....
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; }
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
void set_pointer(T* ptr);
T* m_ptr