智能指针

本文深入探讨了智能指针的概念及其实现方式,包括AutoPtr、ScopedPtr和ScopedArray等不同类型的智能指针,并介绍了它们在C++中的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值