一、 RAII(Resource Acquisition Is Initialization)
资源分配即初始化,定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。
RAII是一种思想,智能指针是RAII思想的一种应用。
小知识:别的语言都有gc垃圾回收,即在堆上创建的内存,在不用这个对象时,会自动回收这些空间,使用智能指针也可以达到这样的效果。
智能指针的定义:
template<class T>
class AutoPtr
{
public:
AutoPtr(T* ptr)
:_ptr(ptr)
{
}
~AutoPtr()
{
printf("_ptr:%p\n", _ptr);//检测是否析构
delete _ptr;
}
private:
T *_ptr;
};
我们知道,一般程序下,若出现异常,程序回终端,则不回走到delete,就造成了内存泄漏。若用智能指针,将创建的指针的地址传入智能指针,出了类的作用域,对象会自动析构,所以开辟的空间也会析构。不管会不会遇到异常,还可以解决忘记delete的诸多问题,减轻了程序员的负担。
#include"smartPstr.hpp"
void DoSomeThing()
{
throw string("抛异常");
}
void testSm()
{
AutoPtr<int> ap1(new int(2));
DoSomeThing();
}
int main()
{
try
{
testSm();
}
catch (string s)
{
cout << s << endl;
}
return 0;
}
所以智能指针有两个特性:1、满足RAII思想 2、像一个指针 3、深浅拷贝
所以现在的问题是指针有何特性,若何时智能指针更像一个指针。
解决深浅拷贝
1、auto_ptr
管理权转移的办法
但是管理权转移是有缺陷的设计,一般不清楚内部设计的会认为被转移权限的指针还存在,容易导致空指针的问题出现,所以很多公司的内部文档明确规定不要使用auto_ptr.
2、Scoped_ptr: 它的设计理念就是防拷贝,简单粗暴。
将拷贝构造和赋值运算符重载定义为私有且不实现,就可做到防拷贝。
3、SharedPtr 共享指针: 引用计数
template<class T>
class SharedPtr
{
public:
SharedPtr(T * pty)
:_ptr(pty)
, _pcount(new int(1))
{
}
SharedPtr(const SharedPtr<T>& sp)
{
_ptr = sp._ptr;
_pcount = sp._pcount;
(*(_pcount))++;
}
~SharedPtr()
{
if (--(*_pcount) == 0)
{
printf("_ptr:%p\n", _ptr);
delete _ptr;
delete _pcount;
}
}
SharedPtr<T>& operator=(SharedPtr<T>& sp)
{
if (this != &sp)
{
if (--(*_pcount) == 0)
{
delete _ptr;
delete _pcount;
}
_ptr = sp._ptr;
_pcount = sp._pcount;
(*_pcount)++;
}
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
protected:
T * _ptr;
int* _pcount;
};
4、weakPtr 解决循环引用 weak_ptr是为配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象
二、探索shared_ptr
上一部分实现的简化版sharedptr看起来不错,起始还有存在以下问题;
1、引用计数更新存在线程安全问题
2、循环引用问题;
3、定置删除器;
知识点:仿函数----函数对象 一个类重载(),可以用这个对象来实现传参