C++---智能指针
在代码中经常忘记释放动态开辟的内存资源,造成内存泄露,并且在操作时要小心谨慎,避免内存泄露,因此产生了只能指针来动态的管理指针所指向的动态资源释放
auto_ptr:管理权的转移操作,存在缺陷
scoped_ptr:一种粗暴模式的防拷贝
shared_ptr:在需要拷贝的地方增加了引用计数功能
weak_ptr:具有弱指针功能,主要配合解决shared_ptr循环引用
auto_ptr
作用:是一种将权限转移的方式(一个指针将一块空间的管理权限交给另一个指针)
template<class T>
class AutoPtr
{
public:
AutoPtr(T* ptr)
:_ptr(ptr)
{}
~AutoPtr()
{
printf("~ptr\n");
delete _ptr;
}
AutoPtr(AutoPtr<T>& ap)
{
_ptr=ap._ptr;
ap._ptr=NULL;
}
AutoPtr<T>& operator=(AutoPtr<T> &ap)
{
if(this!=&ap)
{
delete _ptr;
_ptr=ap._ptr;
ap._ptr=NULL;
}
return *this;
}
T& operator*()
{
return *_ptr;
}
T& operator->()
{
return _ptr;
}
private:
T* _ptr;
};
void TestAutoPtr()
{
AutoPtr<int> apl(new int(10));
AutoPtr<int> ap2(ap1);
//此时ap1已经被置为空了,这时给*ap1赋值就会出现问题
*ap2=200;
AutoPtr<int> ap3(new int(10));
ap3=ap2;//此时ap2被置为NULL
}
auto_ptr优点:实现智能管理指针指向动态资源的释放
缺点:就像拷贝构造函数和赋值运算符函数一样,比如拷贝构造函数,用ap2拷贝ap1,但是当拷贝完成后,发现ap1内部指针被置空了,当我们再次调用ap1时,发现对象已经被释放了,所以程序就会崩溃
scoped_ptr
这个指针以一种简单粗暴的模式直接抛弃的auto_ptr的缺点,这个指针直接不允许拷贝和赋值
实现这种机制的方法有两种:
1.将拷贝构造函数和赋值操作符函数声明为私有的
2.只声明构造函数和赋值操作符函数,不定义
template<class T>
class ScopedPtr
{
public:
ScopedPtr(T* ptr)
:_ptr(ptr)
{}
~ScopedPtr()
{
cout<<"~ScopedPtr()"<<endl;
}
T& operator*()
{
return *_ptr;
}
T& operator->()
{
return _ptr;
}
private:
T* _ptr;
ScopedPtr(const ScopedPtr<T>& sp);
ScopedPtr<T>& operator=(const ScopedPtr<T> &sp);
//用这种简单粗暴的方式防止你在外面调用这两种函数
};
shared_ptr
像指针一样,但会记录有多少个shared_ptrs共同指向一个对象,引用计数,一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。这在非环形数据结构中防止资源泄露很有帮助。这样指针可以共享一块内存,并且不用考虑内存泄露问题
优点:
1.多个指针指向同一个内存空间,释放后,不会造成内存泄露
2.更加安全便捷的管理内存空间
3.可以安全的进行赋值操作符函数和拷贝构造函数
4.多个指针共同管理一块空间,从而更加智能
template<class T>
class SharedPtr
{
public:
SharedPtr(T* ptr,int *pcount)
:_ptr(ptr)
,_pCount(pcount)
{
cout<<"SharedPtr"<<endl;
}
~SharedPtr()
{
if(--(*_pCount)==0)
{
delete[] _ptr;
delete[] _pCount;
cout<<"~SharedPtr"<<endl;
_ptr=NULL;
_pCount=NULL;
}
}
SharedPtr(const SharedPtr<T>& sp)
{
_ptr=sp._ptr;
_pCount=sp._pCount;
++(*_pCount);
}
SharedPtr<T>& operator=(const 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;
};
但是会产生循环引用的问题
struct ListNode
{
SharedPtr<ListNode> _next;
SharedPtr<ListNode> _prev;
ListNode()
:_prev(NULL)
,_next(NULL)
{}
~ListNode()
{
cout<<"delete ListNode"<<endl;
}
}
void TestSharedPtrCycle()
{
SharedPtr<ListNode> cur=new ListNode;
SharedPtr<ListNode> next=new ListNode;
cur->_next=next;
next->_prev=cur;
}
weak_ptr
弱指针,专门解决shared_ptr循环引用问题,只引用不计数
template<class T> class WeakPtr; template<class T>
class SharedPtr
{
friend class WeakPtr<T>;
public:
SharedPtr(T* ptr)
:_ptr(ptr)
,_pCount(new int(1))
{
cout<<"SharedPtr"<<endl;
}
SharedPtr(const SharedPtr<T>& sp)
{
_ptr=sp._ptr;
_pCount=sp._pCount;
(*_pCount)++;
}
SharedPtr<T>& operator=(const SharedPtr<T>& sp)
{
if(this!=&sp)
{
if(--(*_pCount)==0)
{
delete _ptr;
delete _pCount;
}
_pCount=sp._pCount;
_ptr=sp._ptr;
(*_pCount)++;
}
return *this;
}
~SharedPtr()
{
if(--(*_pCount)==0)
{
if(_ptr)
{
delete _ptr;
}
delete _pCount;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
int Count()
{
return *_pCount;
}
protected:
T* _ptr;
int* _pCount;
};
template<class T>
class WeakPtr
{
public:
WeakPtr(SharedPtr<T>& sp)
:_ptr(sp.ptr)
{}
WeakPtr()
:_ptr(NULL)
{}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
protected:
T* _ptr;
};
struct ListNode
{
WeakPtr<ListNode> _next;
WeakPtr<ListNode> _prev;
~ListNode()
{
cout<<"delete ListNode"<<endl;
}
};
void TestSharedPtrCycle()
{
SharedPtr<ListNode> cur=new ListNode;
SharedPtr<ListNode> next=new ListNode;
//使用弱指针来负责cur->next,next->prev的指向,使其引用计数不在加一
cur->_next=next;
next->_prev=cur;
cout<<cur.Count()<<endl;
cout<<next.Count()<<endl;
}
弱指针是指当指针指向原来空间时,引用计数不在进行加1,释放时可直接释放,因此解决了循环引用的问题,不是管理指针,而是配合shared_ptr避免了一次引用计数