文章目录
智能指针的引入
由于C++语言没有自动内存回收机制,每次new出来的内存都要手动delete。
- 忘记delete
- 二次释放
- 异常导致程序过早退出,没有执行delete
用智能指针便可以有效缓解这类问题
理解智能指针
1.从较浅的层面看,智能指针是利用了一种叫做RAII(资源获取即初始化)的技术对普通的指针进行封装。因此智能指针实质是一个对象,行为表现的却像一个指针。
2.每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,析构函数减少引用计数(如果引用计数减至0,则删除基础对象)。
3.智能指针是存储指向动态分配(堆)对象指针的类。除了能够在适当的时间自动删除指向的对象外,他们的工作机制很像C++的内置指针。智能指针在面对异常的时候格外有用,因为他们能够确保正确的销毁动态分配的对象。他们也可以用于跟踪被多用户共享的动态分配对象。
智能指针的简单实现
template<typename T>
class CSmartPtr
{
public:
// 构造函数
CSmartPtr(T *ptr = nullptr)
:mptr(ptr){
}
~CSmartPtr()
{
delete mptr;
}
T& operator*() {
return *mptr; }
const T& operator*()const {
return *mptr; }
T* operator->() {
return mptr; }
private:
T *mptr;
};
int main()
{
CSmartPtr<int> ptr(new int(10));
return 0;
}
由于ptr是栈上的智能指针对象,无论是函数正常执行结束还是异常结束,栈上的对象都会自动调用它的析构函数,保证释放资源。
仔细分析上述代码可以发现,我们没有给智能指针实现,拷贝构造函数,如果执行下面的语句,就会调用默认的拷贝构造函数进行浅拷贝,这样就会导致同一个资源析构两次,这是严重的错误。
CSmartPtr<int> ptr1(ptr);
需要解决的问题
- 浅拷贝问题
- 多个智能指针指向同一个对象时,如何保证资源不被重复释放
解决方法
记录资源的引用计数类
class RefCnt
{
public:
// 给资源添加引用计数
void add(void *ptr)
{
auto it = mrefCntMap.find(ptr);
if (it != mrefCntMap.end())
{
it->second++;
}
else
{
// make_pair(ptr,1);
mrefCntMap.insert({
ptr, 1 });
}
}
// 给资源减少引用计数
void del(void *ptr)
{
auto it = mrefCntMap.find(ptr);
if (it != mrefCntMap.end())
{
if (--(it->second) == 0)
{
mrefCntMap.erase(it);
}
}
}
// 返回指定资源的引用计数
int get(void *ptr)
{
auto it = mrefCntMap.find(ptr);
if (it != mrefCntMap.end())
{
return it->second;
}
return 0;
}
private:
// 一个资源void* 《=》 计数器 int
unordered_map<void*, int> mrefCntMap;
};
自定义的智能指针
template<typename T, typename D = Deletor<T>>
class CSmartPtr
{
public<