针对C++没有实现自己的内存回收机制,所以它引入了智能指针进行内存回收,力求做到内存由用户开辟,系统回收这样就能最大程度避免内存泄漏的发生。具体做法是以智能指针(类)生成一个对象(栈上生成)对开辟的内存(堆上)进行自主回收管理。
- C ++ 98 中引入了auto_ptr智能指针,其宗旨是维护内存所有权的唯一性,具体的做法就是对一个已经开辟内存块只能有一个智能指针指向,如果有新的智能指针对象指向该内存就讲就得智能指针指向断开。
template<typename T>
class Auto_Ptr
{
public:
Auto_Ptr(T* ptr) :mptr(ptr){}
~Auto_Ptr()
{
delete mptr;
mptr = NULL;
}
Auto_Ptr(Auto_Ptr<T>& rhs) //所有权更替
{
mptr = rhs.Release();
}
Auto_Ptr<T>& operator=(Auto_Ptr<T>& rhs) //所有权更替
{
if (this != &rhs)
{
delete mptr;
mptr = rhs.Release();
}
return *this;
}
T& operator*()
{
return *mptr;
}
T* operator->()
{
return mptr;
}
private:
T* Release() //保存旧的智能指针的指向,释放所有权
{
T* ptr = mptr;
mptr = NULL;
return ptr;
}
T* mptr;
};
int main()
{
std::auto_ptr<int> ap1(new int);
std::auto_ptr<int> ap2 = ap1;
*ap1 = 10;
return 0;
}
- C++11又引入了三个新的智能指针unique_ptr、shared_ptr 、weak_ptr,当然新的东西的引入肯定是因为旧的有缺陷。
- unique_ptr:auto_ptr确实是从设计层面上保证了内存所有权的唯一性,但是拷贝构造和赋值运算符重载都会造成智能指针提前失效(所有权更替),所以unique_ptr再次在设计层面上扼杀了它的拷贝构造、赋值运算符重在操作(具体措施就是将它的声明写在智能指针类的私有下,因为没必要做具体实现)。
template<typename T>
class Unique_Ptr
{
public:
Unique_Ptr(T* ptr) :mptr(ptr){}
~Unique_Ptr()
{
delete mptr;
mptr = NULL;
}
T& operator*()
{
return *mptr;
}
T* operator->()
{
return mptr;
}
private:
Unique_Ptr(Unique_Ptr<T>&);
Unique_Ptr<T>& operator =(Unique_Ptr<T>&);
T* mptr;
};
int main()
{
int* p = new int;
Unique_Ptr<int> up1(p);
Unique_Ptr<int> up2(p);
Unique_Ptr<int> up3(p);
return 0;
}
不难看出Unique_Ptr确实解决了指针提前失效的问题,但是指针还是不能共享内存上的数据
- shared_ptr:强智能指针,解决数据共享问题;就单个内存块而言我们应该允许它被多个智能指针指向,具体多少个指针指向必须记录下来,因为释放内存的时机显然是没有指针指向该内存是释放,释放自然要获取内存块的地址,也就是一个指针。一个引用计数,一个指针足以表示单个内存块实时利用信息-----------------设计一个结构体;
- 设计思路:对于shared_ptr来说为它提供一个管理的接口,它对相应内存块对应引用计数的管理也就是对内存的管理,无非是++引用计数、--引用计数、获取引用计数;因此将引用计数操作封装成一个类,并且我们希望对不同类型实例化的智能指针进行统一管理,所以开辟一块内存用于存储它们的信息(地址、引用次数)。
typedef struct ref
{
void* addr;
int count;
}Ref;
Ref ref_count[10];
- 图示:
- 代码:
class Ref_Manage
{
public:
static Ref_Manage* getInstance() //引用计数类管理接口,写成静态方法,所有对象共有
{
if (prm == NULL)
{
prm = new Ref_Manage();
}
return prm;
}
void addRef(void* ptr)
{
if (ptr == NULL)
{
return;
}
int index = find(ptr);
if (index != -1)
{
ref_count[index].count++;
}
else
{
ref_count[cursize].addr = ptr;
ref_count[cursize++].count = 1;
}
}
void delRef(void* ptr)
{
if (ptr == NULL)
{
return;
}
int index = find(ptr);
if (index != -1)
{
if (getRef(ptr) != 0)
{
ref_count[index].count--;
}
}
}
int getRef(void* ptr)
{
if (ptr == NULL)
{
return -1;
}
int index = find(ptr);
if (index == -1)
{
throw std::exception("ptr is error!");
}
return ref_count[index].count;
}
private:
Ref_Manage()
{
cursize = 0;
}
Ref_Manage(const Ref_Manage&);
int find(void* ptr)//下标
{
int index = -1;
for (int i = 0; i < cursize; i++)
{
if (ref_count[i].addr == ptr)
{
index = i;
break;
}
}
return index;
}
typedef struct ref
{
void* addr;
int count;
}Ref;
Ref ref_count[10];
int cursize;
static Ref_Manage* prm;
};
Ref_Manage* Ref_Manage::prm = NULL;
template<typename T>
class Shared_Ptr
{
public:
Shared_Ptr(T* ptr = NULL)
{
mptr = ptr;
rm->addRef(mptr);
}
Shared_Ptr(Shared_Ptr<T>& rhs)
{
mptr = rhs.mptr;
rm->addRef(mptr);
}
Shared_Ptr<T>& operator=(Shared_Ptr<T>& rhs)
{
if (this != &rhs)
{
rm->delRef(mptr);
if (rm->getRef(mptr) == 0)
{
delete mptr;
}
mptr = rhs.mptr;
rm->addRef(mptr);
}
return *this;
}
~Shared_Ptr()
{
rm->delRef(mptr);
if (rm->getRef(mptr) == 0)
{
delete mptr;
}
mptr = NULL;
}
T& operator*()
{
return *mptr;
}
T* operator->()
{
return mptr;
}
private:
T* mptr;
static Ref_Manage* rm;
};
template<typename T>
Ref_Manage* Shared_Ptr<T>::rm = Ref_Manage::getInstance();
int main()
{
int* p = new int;
Shared_Ptr<int> sp1(p);
Shared_Ptr<int> sp2(p);
Shared_Ptr<int> sp3(p);//实现了数据共享
std::shared_ptr<A> pa(new A());//下面的操作会产生强智能指针互相引用的问题
std::shared_ptr<B> pb(new B());
pa->spa = pb;
pb->spb = pa;
return 0;
}
- weak_ptr: 弱智能指针,解决强智能指针相互引用的问题------不加引用计数、不能单独使用,必须配合强智能指针使用(保证了在释放的时候不会因为引用计数不为0而没有正确释放,造成内存泄漏)
引用计数有一个问题就是互相引用形成环,这样两个指针指向的内存都无法释放。需要手动打破循环引用或使用weak_ptr。 weak_ptr是一个弱引用,只引用,不计数。如果一块内存被shared_ptr和weak_ptr同时引用,当所有shared_ptr析构之后, 不管还有没有weak_ptr引用该内存,内存也会被释放。所以weak_ptr不保证它指向的内存一定是有效的,在使用之前需要检 查weak_ptr是否为空指针.
来源:https://blog.csdn.net/zhanxiao5287/article/details/98983445