1.智能指针的引入场景
先来看看以下这种场景
void fun()
{
int *Pa = new int(10);
//
//
if (1)
throw 1;
//
delete Pa;
}
void test1()
{
try
{
fun();
}
catch (...)
{
cout << "未知异常" << endl;
}
}
我们在fun()里通过动态内存开辟了空间,而当我们在delete 前面由于一些必要的原因必须要抛出一个异常时,delete会由于抛出异常后函数提前终止而没有被执行,从而导致内存泄漏。在这种情况下,我们需要一种能够在出作用域时自动释放内存空间的指针,从而使我们能够避免出现内存泄漏的情况,为此我们引入了智能指针。然而智能指针不是指针,它是一个类,但它能够做指针能做的事情,并且能够通过对象生命周期结束时能够自动调用类的析构函数而达到自动释放内存空间的效果。
2.智能指针的实现
我们主要介绍三种智能指针:
auto_ptr
auto_ptr通过“权限转移"使得不同指针指向的同一块空间不会被析构两次,所谓的“权限转移发生在拷贝构造函数和赋值运算符重载函数当中。
template<class T>
class Auto_ptr //权限转换
{
public:
Auto_ptr(T* _ptr=nullptr)
:m_ptr(_ptr)
{
cout << "Use auto_ptr" << endl;
}
Auto_ptr(Auto_ptr<T>& _ap) //拷贝构造函数
{
if (_ap.m_ptr != NULL)
{
m_ptr = _ap.m_ptr;
}
_ap.m_ptr = NULL;
}
Auto_ptr<T>& operator=(Auto_ptr<T>& _ap)
{
if (m_ptr != NULL)
{
delete m_ptr;
m_ptr = NULL;
}
m_ptr = _ap.m_ptr;
_ap.m_ptr = NULL;
return *this;
}
void Show()
{
cout <<"Show()"<< end;
}
~Auto_ptr()
{
cout << "~Auto_ptr()" << endl;
if (m_ptr != NULL)
{
delete m_ptr;
m_ptr = NULL;
}
}
T* operator->() const
{
return this->m_ptr;
}
public:
T *m_ptr;
};
template<class T>
class Scope_ptr //不允许赋值
{
public:
Scope_ptr(T* _ptr=nullptr)
:m_ptr(_ptr)
{
cout << "Scope_Ptr()" << endl;
}
~Scope_ptr()
{
cout << "~Scope_ptr()" << endl;
if (m_ptr != NULL)
{
delete m_ptr;
m_ptr = nullptr;
}
}
T* operator->()
{
return this->m_ptr;
}
private:
Scope_ptr(const Scope_ptr<T>& _ptr);
Scope_ptr<T>& operator=(const Scope_ptr<T>& _ptr);
private:
T* m_ptr;
};
scoped_ptr
scoped_ptr和auto_ptr很相似,都是不允许同一个地址空间被两个或多个不同的指针所指向,但是scoped_ptr将这个工作做得更加彻底,他是不允许拷贝构造函数和赋值运算符重载函数发生调用。
template<class T>
class Scope_ptr //不允许赋值
{
public:
Scope_ptr(T* _ptr=nullptr)
:m_ptr(_ptr)
{
cout << "Scope_Ptr()" << endl;
}
~Scope_ptr()
{
cout << "~Scope_ptr()" << endl;
if (m_ptr != NULL)
{
delete m_ptr;
m_ptr = nullptr;
}
}
T* operator->()
{
return this->m_ptr;
}
private:
Scope_ptr(const Scope_ptr<T>& _ptr);
Scope_ptr<T>& operator=(const Scope_ptr<T>& _ptr);
private:
T* m_ptr;
};
shared_ptr
shared_ptr则显得稍微高端一点,它允许两个指针指向同一块内存地址空间,但是shared_ptr这个类采用了引用计数的方式来维护多个指针指向同一块内存地址空间的问题,它在类中定义了一个指向计数器pCount的指针,当用一个对象创建另一个对象时pCount所指向的计数器值会加1,而在析构函数里,每进来一次析构函数pCount指针所指向的计数器会减1,只有当计数器中的值为0才会释放内存空间。
template<class T>
class Shared_ptr //写时拷贝技术
{
public:
Shared_ptr(T* _ptr=NULL)
:m_ptr(_ptr)
, m_pCount(new int(1))
{
cout << "Shared_ptr()" << endl;
}
Shared_ptr(const Shared_ptr<T>& _sp)
:m_ptr(_sp.m_ptr)
{
cout << "shared_ptr<T>(shared_ptr<T>& _sp)" << endl;
m_pCount = _sp.m_pCount;
++(*m_pCount);
}
Shared_ptr<T>& operator=(Shared_ptr<T>& _sp)
{
if (this->m_ptr != _sp.m_ptr)
{
if (--(*m_pCount) == 0)
{
delete m_ptr;
delete m_pCount;
m_ptr = NULL;
m_pCount = NULL;
}
m_ptr = _sp.m_ptr;
m_pCount = _sp.m_pCount;
++(*m_pCount);
}
return *this;
}
T* operator->()
{
return this->m_ptr;
}
Shared_ptr& operator*()
{
return *this;
}
int Get_Count()
{
cout << "Shared_ptr::Count->";
return *m_pCount;
}
T* Get()
{
return this->m_ptr;
}
~Shared_ptr()
{
if (--(*m_pCount) == 0)
{
cout << "Realse buffer" << endl;
delete m_ptr;
delete m_pCount;
m_ptr = NULL;
m_pCount = NULL;
}
}
private:
T* m_ptr;
int* m_pCount;
};