智能指针

来源:互联网 发布:郭天祥51单片机书 编辑:程序博客网 时间:2024/05/16 15:41

智能指针是什么?
通常,内存是一种被现实管理的资源,这种管理主要是指对原生内存的获取和释放操作,在管理动态分配的内存的时候,最棘手的问题就是决定何时释放这些内存,所以我们引入了一个概念叫做智能指针

智能指针被用来干什么?
简单来说,智能指针就是用于简化内存管理

对于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;}

还有其他几种智能指针不够了解,所以没有写出来,还需要好好看一下
关于以上的智能指针了解的还不是很全面,之后的学习中需要尽快补全!

0 0
原创粉丝点击