智能指针的作用:
堆内存的申请和释放都由程序员自己管理。
普通指针:需要程序员手动释放,容易造成内存泄漏(比如忘记手动释放,或者程序异常)和二次释放的问题。
智能指针:程序结束自己释放,不需要程序员手动释放。所以不存在内存泄漏
智能指针其实就是利用一种叫做RAII(资源获取即初始化)的技术对普通指针进行封装。所以智能指针的实质是个对象(模板类)
智能指针的作用是防止忘记调用delete释放内存和程序异常没有delete,或者多次释放了同一个指针。
智能指针底层代码实现【没考虑线程安全的】
#include<stdio.h>
#include<iostream>
#include<list>
using namespace std;
class ResList
{
public:
// 给ptr资源增加引用计数
void addRef(void *ptr)
{
list<Node>::iterator it1 = nodelist.begin();
while (it1 != nodelist.end())
{
if (it1->_resptr == ptr)
{
it1->_count++;
}
++it1;
}
nodelist.push_back(Node(ptr));
}
// 给ptr资源减少引用计数
int delRef(void *ptr)
{
list<Node>::iterator it1 = nodelist.begin();
while (it1 != nodelist.end())
{
if (it1->_resptr == ptr)
{
if (it1->_count == 1) //只有最后一个指针时,析构
{
nodelist.erase(it1);
return 0;
}
else //还有好多指针指向一个资源,指针数减一
{
it1->_count--;
return it1->_count;
}
}
++it1;
}
return -1;
}
private:
struct Node
{
Node(void *ptr = NULL)
:_resptr(ptr), _count(1){}
void *_resptr; //资源
int _count; //指针数
};
list<Node> nodelist;
};
template<typename T>
class CSmartPtr
{
public:
CSmartPtr(T*ptr = NULL) :mptr(ptr)
{
if (mptr != NULL)
reslist.addRef(ptr);
}
CSmartPtr(const CSmartPtr<T> &src) :mptr(src.mptr)
{
if (mptr != NULL)
reslist.addRef(mptr);
}
CSmartPtr<T>& operator=(const CSmartPtr<T> &src)
{
if (this == &src)
return *this;
if (reslist.delRef(mptr) == 0)
{
delete mptr;
}
mptr = src.mptr;
reslist.addRef(mptr);
return *this;
}
~CSmartPtr()
{
if (reslist.delRef(mptr) == 0)
{
delete mptr;
}
}
T& operator*(){ return *mptr; }
T* operator->(){ return mptr; }
private:
T*mptr;
static ResList reslist;
};
template<typename T>
ResList CSmartPtr<T>::reslist;
智能指针的循环/交叉引用问题
class A
{
public:
shared_ptr<B> _ptrb;
}
class B
{
public:
shared_ptr<A> _ptra;
}
shared_ptr<A> ptra(new A());
shared_ptr<B> ptrb(new B());
//循环引用
ptra->_ptrb = ptrb;
ptrb->_ptra = ptra;
此问题发生的原因是:强智能指针会改变资源引用计数,在循环引用的时候,引用计数被多加了一次。所以该析构的时候,引用计数还为1,则不进行析构操作
解决方法:在创建对象的地方使用强智能指针,其他地方一律使用弱智能指针(因为弱智能指针不能改变资源的引用计数)
弱智能指针不能访问对象的方法,要访问对象,就需要转换为强智能指针
弱智能指针提升为强智能指针的方法:
shared_ptr<A> ptra = _ptra.lock();
if(ptra != NULL) //判断是否为NULL,从而判断是否提升成功。当提升成功后,资源的引用计数随即加一
{
ptra -> func();
}
库里面提供的智能指针
头文件:#include<memory>
不带引用计数的智能指针===》会发生浅拷贝
auto_ptr -- 会将原来的auto_ptr置空,只有最新的auto_ptr才能访问资源(就是一块资源只能一个指针访问,释放旧指针)
因为会释放旧的指针,所以我们禁止使用该指针
scope_ptr
unique_ptr --- 与shared_ptr不同,unique_ptr拥有它所指向的对象,在某一时刻,只能有一个unique_ptr指向特定的对象。当unique_ptr被销毁时,它所指向的对象也会被销毁。因此不允许多个unique_ptr指向同一个对象,所以不允许拷贝与赋值。
带引用计数的智能指针
shared_ptr 强智能指针【可改变资源的引用计数】,是线程安全的
weak_ptr 弱智能指针【不能改变资源的引用计数】
没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况
相关资料:
C++11中智能指针的原理、使用、实现
C++面试题(四)——智能指针的原理和实现
unique_ptr的使用和陷阱: https://blog.csdn.net/qq_33266987/article/details/78784286