某种情况下,我们完成了对空间的申请,程序某些问题或者异常的出现,对空间申请完成后并没及时的释放,导致内存泄漏。为此,出现了智能指针的概念,用过类的销毁时调用析构函数的特性,将智能指针封装成一个类,在指针销毁时,同时完成对其空间的释放。
Auto_ptr
Auto_ptr的缺陷是一个指针给其他指针进行赋值或者拷贝时,会导致指针失效。
#pragma once
#include<iostream>
template<class T>
class Auto_ptr
{
public:
Auto_ptr(T*& ptr)
:_ptr(ptr)
{}
Auto_ptr(Auto_ptr<T>& AP)
:_ptr(AP._ptr)
{
AP._ptr = NULL;
}
Auto_ptr<T> operator=(Auto_ptr<T>& AP)
{
if (this != &AP)
{
if (_ptr)
{
delete _ptr;
}
_ptr = AP._ptr;
AP._ptr = NULL;
}
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
~Auto_ptr()
{
delete _ptr;
}
private:
T* _ptr;
};
Scoped_ptr
为了对Auto_ptr优化,Scoped_ptr采取了防止拷贝的手段。将其的拷贝构造和赋值运算符的重载只进行申明,并不定义,且将其设为private防止类外对其申明。
#pragma once
#include<iostream>
template<class T>
class Scoped_ptr
{
public:
Scoped_ptr(const T*& ptr)
:_ptr(ptr)
{}
~Scoped_ptr()
{
if (_ptr)
delete _ptr;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
Scoped_ptr(const Scoped_ptr<T>&);
Scoped_ptr<T> operator=(const Scoped_ptr<T>&);
private:
T* _ptr;
};
Scoped_arry
用于指向一个数组
#pragma once
#include<iostream>
template<class T>
class Scopedarry
{
public:
Scopedarry(const T* ptr)
:_ptr(ptr)
{}
~Scopedarry()
{
if (_ptr)
delete[] _ptr;
}
T& operator[](const size_t pos)
{
return _ptr[pos];
}
private:
Scopedarry(const Scopedarry<T>&);
Scopedarry<T>& operator=(const Scopedarry<T>&);
private:
T* _ptr;
};
Shared_ptr
为了使智能指针类更加接近指针的功能,Shared_ptr采用了引用计数,防止同一块空间被多个指针指向,导致一块空间被释放多次。
指向相同空间的指针都有相同的一块区域来记录该空间目前被多少指针管理。
引用计数只要没有变为0,该空间就不会被释放。
#pragma once
#include<iostream>
#include"Weak_ptr.h"
template<class T>
class Shared_ptr
{
friend class Weak_ptr<T>;
public:
Shared_ptr(const T* ptr=NULL)
:_ptr(ptr)
, _refcount(new int(1))
{}
Shared_ptr(const Shared_ptr<T>& sp)
:_ptr(sp._ptr)
, _refcount(sp._refcount)
{
*_refcount++;
}
Shared_ptr<T>& operator=(const Shared_ptr<T>& sp)
{
if (sp._ptr!= _ptr)
{
if (--(*_refcount) == 0)
{
delete _ptr;
delete _refcount;
}
_ptr = sp._ptr;
_refcount = sp._refcount;
*_refcount++;
}
return *this;
}
~Shared_ptr()
{
if (--(*_refcount) == 0)
{
if (_ptr)
{
delete _ptr;
}
delete _refcount;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
int* _refcount;
};
Shared_arry
#pragma once
#include<iostream>
template<class T>
class Sharedarry
{
public:
Sharedarry(const T* ptr)
:_ptr(ptr)
, _refcount(new int(1))
{}
Sharedarry(const Sharedarry<T>& sa)
:_ptr(sa._ptr)
, _refcount(sa._refcount)
{
++(*_refcount);
}
~Sharedarry()
{
if (--(*_refcount) == 0)
{
delete[] _ptr;
delete _refcount;
}
}
Sharedarry<T>& operator=(const Sharedarry<T>& sa)
{
if (_ptr != &sa._ptr)
{
if (--(*_refcount) == 0)
{
delete[] _ptr;
delete _refcount;
}
_ptr = sa._ptr;
_refcount = sa._refcount;
*_refcount++;
}
}
T& operator[](const size_t& pos)
{
return _ptr[pos];
}
private:
T* _ptr;
int* _refcount;
};
Shared_ptr实现以后,我们发现了一种场景
struct node
{
Shared_ptr<node> _next;
Shared_ptr<node> _prev;
};
int main()
{
Shared_ptr<node> n1 = new node;
Shared_ptr<node> n2 = new node;
n1->_next = n2;
n2->_prev = n1;
return 0;
}
在这种场景下,我们最后的空间并没有的到释放。
n1需要释放时,此时指向这块空间的有n1和n2的prev,引用计数为2,引用计数减1。空间并没有释放。
当n2释放时,管理此块空间的有n2和n1的next,引用计数为2,引用计数减1。空间也没得到释放。
形成引用计数。
要解决引用计数的问题,我们引入Weak_ptr辅助Shared_ptr,并不增加引用计数,也不对指针进行管理。
#pragma once
#include<iostream>
#include"Shared_ptr.h"
template<class T>
class Weak_ptr
{
public:
Weak_ptr()
:_ptr(NULL)
{}
Weak_ptr(const Shared_ptr<T>& sp)
:_ptr(sp._ptr)
{}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
解决引用计数需要Shared_ptr和Weak_ptr配合使用。
#include<iostream>
#include"Shared_ptr.h"
struct node
{
Weak_ptr<node> _next;
Weak_ptr<node> _prev;
};
int main()
{
Shared_ptr<node> n1 = new node;
Shared_ptr<node> n2 = new node;
n1->_next = n2;
n2->_prev = n1;
return 0;
}