写C/C++程序常常苦恼于内存的释放管理,需要程序开发人员自己去管理,拥有内存控制权限的同时也带来了很多头疼的释放操作,从而导致内存的泄露。那到底有哪些“不正规”操作导致了内存泄漏呢:
- new了一个对象忘记delete的
- delete后忘记将指针置为NULL的
- 异常或者中断(程序退出)发生在delete之前的
可见new delete需要耗费程序开发人员不少心思去细致的处理,实在是繁琐,因此,智能指针应运而生。智能指针在C++11中引入,实现了动态内存管理。其shared_ptr采用引用计数的方式管理所指向的对象。当有一个新的shared_ptr指向同一个对象时(复制shared_ptr等),引用计数加1。当shared_ptr离开作用域时,引用计数减1。当引用计数为0时,释放所管理的内存。这样做的好处在于缓解了程序员手动释放内存的压力。之前,为了处理程序中的异常情况,往往需要将指针手动封装到类中,通过析构函数来释放动态分配的内存;现在这一过程就可以交给shared_ptr去做了。
最近阅读安卓源码,发现其底层C++代码就封装了智能指针,因此我们今天就自己实现一下智能指针,当做轮子。
1.大致框架
按照标准类的定义,我们来实现一个动态模板类的雏形-----sp(smart ptr)。
template<typename T>
class sp {
public:
//----------------------------------------
sp():ptr(nullptr){}
sp(T* other);
sp(const sp<T>& other);
~sp();
private:
T* ptr;
int* use_count;
};
template<typename T>
sp<T>::sp(T * other):ptr(other)
{
use_count = new int(1);
}
template<typename T>
sp<T>::sp(const sp<T>& other)
{
ptr = other.ptr;
use_count = other.use_count;
++(*use_count);
}
template<typename T>
sp<T>::~sp()
{
if (--(*use_count) == 0) {
delete ptr;
delete use_count;
ptr = nullptr;
use_count = nullptr;
}
}
2.添加常用操作。
仔细分析一下,这样显然是满足不了日常需求的。
- 此模式下传参只能传T*类型的,显然不满足类型转换的需求
- 没有常用的操作运算符,需要优化
- 指针提取和解引用太过麻烦
因此我们可以做出适当优化,下面给出程序:
#define COMPARE(_op_)
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; \
} \
template <typename T>
class sp {
public:
//----------------------------------------
sp():m_ptr(nullptr){}
template<typename U> sp(U* other); // NOLINT, implicit
template<typename U> sp(const sp<U>& other); // NOLINT, implicit
~sp();
template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (U* other);
// 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:
T* m_ptr;
int* use_count;
};
template<typename T> template<typename U>
sp<T>::sp(U* other) : m_ptr(other)
{
if (m_ptr) {
use_count = new int(1);
cout << "P constructor called. " <<*use_count<< endl;
}
}
template<typename T> template<typename U>
sp<T>::sp(const sp<U>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) {
use_count = other.use_count;
++(*use_count);
cout << "SP constructor called. " <<*use_count<< endl;
}
}
template<typename T>
sp<T>::~sp()
{
if (--(*use_count) == 0) {
cout << "Destructor called."<<endl;
delete m_ptr;
delete use_count;
m_ptr = nullptr;
use_count = nullptr;
}
}
template<typename T> template<typename U>
sp<T>& sp<T>::operator = (const sp<U>& other) {
cout << "SP copy called." << endl;
++(*other.use_count);
if (--(*use_count) == 0) {
delete m_ptr;
delete use_count;
}
m_ptr = other.m_ptr;
use_count = other.use_count;
return *this;
}
template<typename T> template<typename U>
sp<T>& sp<T>::operator = (U* other)
{
cout << "P copy called."<<endl;
if (--(*use_count) == 0) {
delete m_ptr;
delete use_count;
}
m_ptr = other;
*use_count = 1;
return *this;
}
还有一些运算符没有重载,天色已完,改日再叙。