版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
今天遇到一个问题需要记录一下,C++中的RAII机制对于内存泄漏问题有了很大的帮助。当我们在拿到一块堆空间的时候,就应该用智能指针包裹起来,当对象生命周期结束的时候会自动释放申请的内存。
智能指针的类型常用的有三种,shared_ptr,unique_ptr,weak_ptr。三种智能指针各有特点,简单而言,shared_ptr有引用计数,unique_ptr一个对象只能指向一块给定内存(不支持拷贝和赋值),weak_ptr是一种“弱”智能指针,不控制对象的生命周期,也不增加引用计数。
一般都是选择shared_ptr,由于其引用计数功能,每当拷贝一个对象,引用计数就会增加1,同理,当一个shared_ptr对象销毁时候,计数器就会减少1,当计数器为0的时候,shared_ptr就会自动释放其管理的对象。Shared_ptr简单实现。
/*
* @Description: share_ptr的实现,注意不能用一个生指针给智能指针初始化(所以构造函数要声明为显式)
*/
#ifndef _SHARE_PTR_H
#define _SHARE_PTR_H
#include <iostream>
#include <string>
template<typename T>
class My_Share_Ptr{
public:
My_Share_Ptr():a(NULL),num(new int(0)){ }
explicit My_Share_Ptr(T *ptr):a(ptr),num(new int(1)){ }
My_Share_Ptr(const My_Share_Ptr& ptr):a(ptr.a),num(ptr.num)
{
(*num)++;//引用计数+1
}
My_Share_Ptr operator =(const My_Share_Ptr& ptr);
~My_Share_Ptr(){
if(a && (*num)--){
delete a;
delete num;
}
}
public:
T& operator*();
T* operator->();
inline T* get() const {
return a;
}
inline int user_count() const{
return *num;
}
private:
T *a;//内部指针
int* num;//引用计数,注意这里一定要指针
};
#endif
#include "share_ptr.h"
template<typename T>
My_Share_Ptr<T> My_Share_Ptr<T>::operator =(const My_Share_Ptr<T>& ptr){
if(this==&ptr){
return *this;
}
*num--;
if(*num==0){
delete num;
delete a;
}
num=ptr.num;
*num++;
a=ptr->a;
return *this;
}
template<typename T>
T& My_Share_Ptr<T>::operator *(){
if(num==0){
return (T*) 0;
}
return *a;
}
template<typename T>
T* My_Share_Ptr<T>::operator->(){
if(num==0){
return 0;
}
return a;
}
接下来进入重点,最近在用shared_ptr的时候发现循环引用的问题,这里需要注意一下。解决的方法就是在类中,用weak_ptr替代shared_ptr。
#include <iostream>
#include <memory>
using namespace std;
class TestA;
class TestB;
class TestA{
public:
shared_ptr<TestB> ptr1;
public:
TestA():ptr1(NULL){ }
};
class TestB{
public:
shared_ptr<TestA> ptr2;
public:
TestB():ptr2(NULL){ }
};
int main(){
//以下四句会造成一个互相赋值的僵局(有点类似于死锁,但是不是申请共享资源,而是形成一个链状)
shared_ptr<TestA> ptrA(new TestA);
shared_ptr<TestB> ptrB(new TestB);
ptrA->ptr1=ptrB;
ptrB->ptr2=ptrA;
return 0;
}
无论ptrA还是ptrB,都会因为引用计数没有到达0,无法释放在堆上的资源。