[C++]:智能指针

1.为什么需要智能指针?

当我们写一个new语句时,一般就会立即把delete语句直接也写了,但是我们不能避免程序还未执行到delete时就跳转了或者在函数中没有执行到最后的delete语句就返回了,如果我们不在每一个可能跳转或者返回的语句前释放资源,就会造成内存泄露。使用智能指针可以很大程度上的避免这个问题,因为智能指针就是一个类,当超出了类的作用域是,类会自动调用析构函数,析构函数会自动释放资源。

2.什么是智能指针?

智能指针是一种基于RAII思想的特殊的类,它封装了一个指针,重载了->,*运算符,实现了C++内存自动回收机制。
RAII: 是一种利用对象生命周期来控制程序资源(如内存、文件句 柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的 时候释放资源。这种做法使得不需要显示的释放资源、对象所需资源在其生命周期内都有效。

2.1 std::auto_ptr

先看如下demo:

#include<memory>
class A {
public:
	A() { std::cout << "A()" << std::endl; }
	~A() { std::cout << "~A()" << std::endl; }
	int m;
};
int main()
{
	std::auto_ptr<A> a(new A);
	std::auto_ptr<A> cpoy(a);
	a->m = 100;
	return 0;
}

执行代码我们可以看到,输出“A()”后程序会崩溃,这就是auto_ptr的缺陷:当对象拷贝或者赋值后,前面的对象就悬空了,从而执行a->m时解引用失败。

2.1.1模拟实现auto_ptr

#include<iostream>
template<class T>
class Auto_ptr{
    public:
        Auto_ptr(T* ptr = nullptr):_ptr(ptr){}
        ~Auto_ptr(){if(_ptr) delete _ptr;}
        Auto_ptr(Auto_ptr<T> &ap)
          :_ptr(ap._ptr)
        {
            ap._ptr = nullptr;
        }
        Auto_ptr<T>& operator=(Auto_ptr<T> &ap){
            if(this != ap){
                if(_ptr)
                  delete _ptr;
                _ptr = ap._ptr;
                ap._ptr = nullptr;
            }
            return *this;
        }
        T& operator*(){
            return *_ptr;
        }
        T& operator->(){
            return _ptr;
        }
    private:
        T *_ptr;
};

从实现原理来看,当拷贝或者赋值时,会销毁当前对象ap,所以会出现拷贝或赋值之后,前面的对象就会悬空。

2.2 std::unique_ptr

#include<memory>
class a {
public:
	a() { std::cout << "a()" << std::endl; }
	~a() { std::cout << "~a()" << std::endl; }
	int m;
};

int main()
{
	std::unique_ptr<a> up(new a);
	std::unique_ptr<a> copy(up);
	std::unique_ptr<a> ap(new a);
	ap = up;
	return 0;
}

执行上面的程序,会发现编译不通过,并且报错“调用已删除的函数”,这是c++11的防拷贝方式。这也印证了unique_ptr的特点,直接私有拷贝构造和赋值函数,防止拷贝或者赋值。

2.2.1 模拟实现unique_ptr

#include<iostream>
template<class T> 
class UniquePtr{
    UniquePtr(T* ptr = nullptr)
        :_ptr(ptr){}
    ~UniquePtr(){if(_ptr) delete _ptr;}
    T& operator*(){return *_ptr;}
    T* operator->(){return _ptr;}
    private:
        UniquePtr(UniquePtr<T>const &) = delete;
        UniquePtr& operator=(UniquePtr<T>const &) = delete;
    private:
        T *_ptr;
};

2.3 std::shared_ptr

share_ptr的使用方式如下:

int main()
{
	std::shared_ptr<a> sp(new a);
	std::shared_ptr<a> copy(sp);
	std::cout << "use_count:" << sp.use_count() << std::endl;
	std::cout << "use_count:" << copy.use_count() << std::endl;
	return 0;
}

可以看到,share_ptr是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。

2.3.1 模拟实现shared_ptr

shared_ptr原理:

  1. shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
  2. 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
  3. 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源。
  4. 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指 针了。
#include<mutex>
#include<thread>
#include <iostream>
template<class T>
class SharedPtr{
    public:
        SharedPtr(T* ptr = nullptr)
          :_ptr(ptr)
          ,_count(new int(1))
          ,_mutex(new std::mutex)
        {}
        SharedPtr(const SharedPtr<T>& sp)
          :_ptr(sp._ptr)
          ,_count(sp._count)
          ,_mutex(sp._mutex)
        {
            AddCount();
        }
        SharedPtr<T>& operator=(const SharedPtr<T>& sp){
            if(_ptr != sp._ptr){
                Release();
                _ptr = sp._ptr;
                _count = sp._count;
                _mutex = sp._mutex;
                AddCount();
            }
            return *this;
        }
        ~SharedPtr(){
            Release();
        }
        T& operator*(){return *_ptr;}
        T& operator->(){return _ptr;}
        int usecount(){return *_count;}
        T* Get(){return _ptr;}
    private:
        void AddCount(){
            _mutex->lock();
            (*_count)++;
            _mutex->unlock();
        }
        void Release(){
            bool deletefg = false;
            _mutex->lock();
            if(--(*_count) == 0){
               delete _ptr;
               delete _count;
               deletefg = true;
            }
            _mutex->unlock();
            if(deletefg == true)
               delete _mutex;
        }
    private:
        T* _ptr;
        int* _count;
        std::mutex* _mutex;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值