智能指针是什么?
通常,内存是一种被现实管理的资源,这种管理主要是指对原生内存的获取和释放操作,在管理动态分配的内存的时候,最棘手的问题就是决定何时释放这些内存,所以我们引入了一个概念叫做智能指针!
智能指针被用来干什么?
简单来说,智能指针就是用于简化内存管理
对于c++而言,智能指针是一些在行为上类似于普通指针的类,因为其中有显式访问和间接访问,而且该类还封装了一些内存管理或者资源管理policy
智能指针模板,封装了两种不同的所有权模型:独占和共享
1.与直接操作的原生指针相比,使用独占模型几乎不需要耗费额外的开销。当操作动态分配的对象是,使用这种policy的指针可以用于处理异常抛出
2.使用共享模型的时候有时会导致非常复杂的对象生命周期问题。在这种情况下,我们通常建议让程序自身来处理对象的生命,也就是所,成语远不需要考虑对象的生命周期
在这里,我们对概念性的东西来具体化一下,下面我们来看看几种智能指针
AutoPtr
这是一种利用资源转移,职能管理单个空间的,那我们来看看新库(boost)中这种指针的实现吧
一.新版的AutoPtr
1.当不给出拷贝构造函数的时候
template<typename T>
class AutoPtr
{
public:
AutoPtr(T* p) //p-->本意不可被修改,但是_p是可以被修改的,所以p不能设置为const T* p
:_p(p)
{}
/*AutoPtr(const AutoPtr<T>)
{}*/
~AutoPtr()
{
if (NULL != _p)
{
delete _p;
}
}
private:
T* _p;
};
void FunTest()
{
int *p = new int;
AutoPtr<int> ap(p);
AutoPtr<int> ap1(ap);//没有创建拷贝构造函数,系统默认给一个拷贝构造,默认
//拷贝构造函数值拷贝,指向所拷贝空间内存,可能会导致到此多次析构导致崩溃
//系统所默认的拷贝构造函数和赋值运算符所做的事情是一样的,都是浅拷贝
}
2.解决因多个对象指向一个空间释放多次而造成程序崩溃问题的方法
template<typename T>
class AutoPtr
{
public:
AutoPtr(T* p = NULL)
:_p(p)
{}
AutoPtr(AutoPtr<T>& ap)
:_p(ap._p)
{
ap._p = NULL;
}
~AutoPtr()
{
if (NULL != _p)
{
delete _p;
}
}
private:
T* _p;
};
void FunTest()
{
int *p = new int;
AutoPtr<int> ap(p);
AutoPtr<int> ap1(ap);//让ap去指向一个空的空间,防止ap1指向的空间被析构多次而造成导致程序崩溃
AutoPtr<int> ap2;
ap2 = ap1;//ap1 和 ap2 还是指向同一段空间,造成了第一个问题,这时候只要给出赋值运算符的重载就可以了
}
3.解决2中出现的问题
template<typename T>
class AutoPtr
{
public:
AutoPtr(T* p = NULL)
:_p(p)
{}
AutoPtr(AutoPtr<T>& ap)
:_p(ap._p)
{
ap._p = NULL;
}
//AutoPtr<T>& operator=(AutoPtr<T>& ap)
//{
// if (this != &ap)
// {
// }
// return *this;
//}//可以,但是不太好 ap1(p),ap2(p),ap2=ap1,这样的话就无法判断
//修正
AutoPtr<T>& operator=(AutoPtr<T>& ap)
{
if (_p != ap._p)
{
if (NULL != _p)
{
delete _p;
}
_p = ap._p;
ap._p = NULL;
}
return *this;
}
~AutoPtr()
{
if (NULL != _p)
{
delete _p;
}
}
//解引用的重载
T* operator*()
{
return *_p;
}
//显示重载
T* operator->()
{
return _p;
}
T* Get()
{
return _p;
}
private:
T* _p;
};
void FunTest()
{
int *p = new int;
//AutoPtr<int> ap(p);
//AutoPtr<int> ap1(ap);//让ap去指向空,防止ap1指向的空间被析构多次而造成导致程序崩溃
//AutoPtr<int> ap2;
//ap2 = ap1;//利用赋值运算符的重载,让ap1指向空 ,防止ap2指向的空间被析构多次而造成程序崩溃
}
二.旧版的AutoPtr
template<typename T>
class AutoPtr
{
public:
AutoPtr(T* p = NULL)
:_p(p)
{
if (_p)
{
_owner = true;
}
}
AutoPtr(AutoPtr<T>& ap)
:_p = ap._p
, _owner(ap._owner)
{
ap._owner = false;
}
AutoPtr<T>& operator=(AutoPtr<T>& ap)
{
if (_p != ap._p)
{
if (_owner)
{
delete _p;
}
_p = ap._p;
_owner = true;
ap._owner = false;
}
return *this;
}
~AutoPtr()
{
if (_owner)
{
delete _p;
}
}
private
T* _p;
bool _owner;
};
/*
其中方法上是没有问题的,当我们能正确使用智能指针,也就是一个智能指针交给一个对象去管理,一对一的关系,就可以避免不必要的麻烦
但是,上述问题可能在我们写代码的过程中存在,所以还是注意,换句话说,不要用AutoPtr*/
在不考虑非正规使用智能指针的前提下,第一种好一点,第二种用ap1拷贝构造ap2之后释放ap2
空间,那么ap1就成为了一个野指针,所以两种都不能用!!!!!!!!!!
ScopedPtr
相对于AutoPtr来说,这是一种防拷贝的智能指针,管理单个空间。主要特点是不能调用赋值运算符的重载和拷贝构造函数(既是优点也是缺点)
先面来看看他的代码实现
template<typename T>
class ScopedPtr
{
public:
ScopedPtr(T* p = NULL)
:_p(p)
{}
~ScopedPtr()
{
if (_p != NULL)
{
delete _p;
_p = NULL;
}
}
T* operator*()
{
return *_p;
}
T* operator->()
{
return _p;
}
T* Get()
{
return _p;
}
private:
T* _p;
private:
ScopedPtr(ScopedStr<T>&);
ScopedPtr<T>& operator=(const ScopedPtr<T>&);
};
void FunTest()
{
ScopedPtr<int> sp(new int);
/*ScopedPtr<int> sp1(sp); (拷贝构造)不行 */
/*ScopedPtr<int> sp2(new int);
sp2 = sp; (赋值运算符重载)不行*/
}
ScopedArray
这是存在于boost库中,类似于标准库中的Vector,实现动态连续空间的管理
下面是它的代码实现
template<typename T>
class ScopedArray
{
public:
ScopedArray(T* p = NULL)
:_p(p)
{}
T& operator[](size_t index)
{
return _p[index];
}
const T& operator[](size_t index)const
{
return _p[index];
}
~ScopedArray()
{
if (NULL != _p)
{
delete[]_p;
}
}
T* operator*()
{
return *_p;
}
T* operator->()
{
return _p;
}
T* Get()
{
return _p;
}
private:
T* _p;
private:
ScopedArray(ScopedArray<T>&);
ScopedArray<T>& operator=(const ScopedArray<T>&);
};
void FunTest()
{
int i = 0;
ScopedArray<int> sa(new int[10]);
sa[0] = 10;
sa[2] = 100;
sa[5] = 1000;
for (i = 0; i < 10; i++)
{
cout << sa[i] << endl;
}
}
将FunTest()函数在mian函数中调用即可
最后我们引入了一种关于具有程序计数器的智能指针SharedPtr
template<typename T>
class SharedPtr
{
public:
SharedPtr(T* p = NULL)
:_p(p)
, _pCount(NULL)
{
if (NULL != _p)
_pCount = new int(1);
}
SharedPtr(const SharedPtr<T>& sp)
:_p(sp._p)
, _pCount(sp._pCount)
{
if (_pCount == NULL)
{
;
}
else
{
++(*_pCount);
}
}
SharedPtr<T>& operator=(const SharedPtr<T>& sp)
{
if (_p != sp._p)
{
if (_p == NULL)
{
_p = sp._p;
_pCount = sp._pCount;
}
else
{
if (0 == --(*_pCount))
{
delete _p;
delete _pCount;
}
_p = sp._p;
_pCount = sp._pCount;
}
if (_pCount != NULL)
{
++(*_pCount);
}
}
return *this;
}
~SharedPtr()
{
if (_pCount == NULL)
{
;
}
else
{
if (0 == --(*_pCount))
{
delete _p;
delete _pCount;
_p = NULL;
_pCount = NULL;
}
}
}
private:
T* _p;
int* _pCount;
};
void FunTest()
{
SharedPtr<int> sp(new int);
SharedPtr<int> sp1(sp);
}
int main()
{
FunTest();
system("pause");
return 0;
}
还有其他几种智能指针不够了解,所以没有写出来,还需要好好看一下
关于以上的智能指针了解的还不是很全面,之后的学习中需要尽快补全!