浅谈C++智能指针

为什么要使用智能指针?

  • 因为在C++中没有自动的回收机制,在每次new开辟新的空间以后,就要用delete来对开辟的空间进行释放。在代码比较多的时候,很有可能出现忘记deleted释放,这让就会出现内存泄漏。在一段进行了try/catch的代码段里面,即使你写入了delete,也有可能因为发生异常,程序进入catch块,从而忘记释放内存,造成内存泄漏。

  • 智能指针可以有效的避免这个问题。智能指针的实质是一个对象,但是表现的行为确实指针。遵循RAII的规则(RAII,也称为“资源获取就是初始化”,是c++等编程语言常用的管理资源、避免内存泄露的方法。它保证在任何情况下,使用对象时先构造对象,最后析构对象。)。

常见的几种智能指针:

  • auto_ptr 管理权转移,带有缺陷的设计,会释放一个空间多次,造成内存泄漏。
    模拟实现auto_ptr
template<class T>
class AutoPtr
{
public:
    AutoPtr(T* ptr = NULL)
        :_ptr(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;
    }

        ~AutoPtr()//析构
        {
            if (_ptr)
            {
                cout << _ptr << endl;
                delete _ptr;
                _ptr = NULL;
            }
        }

        T& operator*()
        {
            return *_ptr;
        }

        T& operator->()
        {
            return _ptr;
        }
protected:
    T* _ptr;
};

int main()
{
    AutoPtr<int> ap1(new int(1));
    AutoPtr<int> ap2 = ap1;//ap2(ap1)error
    //ap1地址指向随机
    AutoPtr<int> ap3(new int(2));
    ap2 = ap3;//ap3地址为随机值
    system("pause\n");
    return 0;
}
//auto_ptr会使原来的数据丢失,所以不建议使用。
  • scoped_ptr 防拷贝,高效,简洁。不需要拷贝/赋值的时候使用。在使用的时候,对赋值、拷贝操作只声明不定义。
    模拟实现scoped_ptr:
template<class T>
class ScopedPtr
{
public:
    //RAII
    ScopedPtr(T* ptr = NULL)
        :_ptr(ptr){}

    ~ScopedPtr()
    {
        if (_ptr)
        {
            delete _ptr;
        }
    }

    T& operator*()
    {
        return *_ptr;
    }

    T& operator->()
    {
        return _ptr;
    }
protected:
    T* _ptr;
private://只声明不定义,且声明为私有
    ScopedPtr(const ScopedPtr<T>& sp);
    ScopedPtr<T>& operator = (const ScopedPtr<T>&);
};

int main()
{
    ScopedPtr<int> sp1(new int(3));
    //ScopedPtr<int> sp2(sp1);//错误
    return 0;
}
  • share_ptr 共享(引用计数)管理,支持赋值/拷贝。缺陷是循环引用,使用weak_ptr能辅助的解决这个问题。
    模拟实现share_ptr:
template<class T>
struct Delete  //清理单个空间
{
    void operator()(T* ptr)//定制删除器(仿函数)
    {
        delete ptr;
    }
};

template<class T>
class DeletArray//清理数组
{
public:
    void operator()(T* ptr)
    {
        delete[] ptr;
    }
};

template<class T,class D = Delete<T>>//默认是delete,不是delete[]
class SharedPtr
{
public:
    SharedPtr(T *ptr)
        :_ptr(ptr)
        , _countRef(new int(1)){}



    SharedPtr<T,D>& operator= (const SharedPtr<T,D>& sp)//赋值运算符的重载
    {
        if (_ptr != sp._ptr)
        {
            Release();
        _ptr = sp._ptr;
        _countRef = sp._countRef;
        ++(*_countRef);
         }
        return *this;
    }

    SharedPtr(const SharedPtr<T, D>& sp)//拷贝构造
        :_ptr(sp._ptr)
        , _countRef(sp._countRef)
    {
        ++(*_countRef);
    }

    inline void Release()
    {
        if (--(*_countRef) == 0)
        {
            cout << _ptr << endl;
            _del( _ptr);
            delete _countRef;
        }
    }

    ~SharedPtr()
    {
        Release();
    }

    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }

    int UseCount()//引用计数
    {
        return *_countRef;
    }

protected:
    T* _ptr;
    int* _countRef;//引用计数

    D _del;//定制的仿函数删除器
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值