智能指针

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内 存、文件句柄、网络连接、互斥量等等)的简单技术。 在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在 对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。

这种做 法有两大好处:

  • 不需要显式地释放资源。
  • 采用这种方式,对象所需的资源在其生命期内始终保持有效。

先实现一个普通的智能指针

template<class T>
class smart_ptr
{
public:
    smart_ptr(T* ptr)
        :_ptr(ptr)
    {}

    ~smart_ptr()
    {
        if (_ptr)
        {
            delete _ptr;
            _ptr = nullptr;
        }
    }

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

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

private:
    T* _ptr;
};

即使中间有异常抛出,当作用域走完生命周期,析构函数会自动调用。完成析构,就不会发生了内存泄漏问题。

unique_ptr 基本实现

template<class T>
class unique_ptr
{
public:
    unique_ptr(T* ptr)
        :_ptr(ptr)
    {}

    ~unique_ptr()
    {
        if (_ptr)
        {
            delete _ptr;
            _ptr = nullptr;
        }
    }

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

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

    unique_ptr(unique_ptr& p) = delete;
    unique_ptr operator=(unique_ptr& p) = delete;

private:
    T* _ptr;
};

unique_ptr跟普通智能指针区别不大 只是unique_ptr是不允许用拷贝和赋值的

shared_ptr基本实现

它能使用拷贝和赋值 使用的是一种计数的方法。

    template<class T>
    class shared_ptr
    {
    public:
        shared_ptr(T* ptr)
            :_ptr(ptr)
            , pcount(new int(1))
        {}

        ~shared_ptr()
        {
            Relses();
        }

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

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

        shared_ptr(shared_ptr& p)
            :_ptr(p._ptr)
            ,pcount(p.pcount)
        {
            (*pcount)++;
        }

        void Relses()
        {
            if (--(*pcount) == 0 && _ptr)
            {
                cout << _ptr << endl;
                delete _ptr;
                delete pcount;
                _ptr = nullptr;
                pcount = nullptr;
            }
        }

        shared_ptr& operator=(shared_ptr& p)
        {
            if (_ptr != p._ptr)//当两个指针地址不相同才赋值
            {
                Relses();

                _ptr = p._ptr;
                pcount = p.pcount;
                *(pcount)++;
            }
            return *this;
        }

    private:
        T* _ptr;
        int* pcount;
    };

weak_ptr基本实现

此智能指针是用来辅助shared_ptr的 用来解决循环引用问题

    template<class T>
    class weak_ptr
    {
    public:
        weak_ptr()
            :_ptr(nullptr)
        {}

        weak_ptr(const shared_ptr& p)
            :_ptr(p.get())
        {}

        weak_ptr& operator=(const shared_ptr& p)
        {
            if (_ptr != p.get())
            {
                _ptr = p.get();
            }
            return *this;
        }

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

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

    public:
        T* _ptr;
    };

循环引用问题

    struct listnode
    {
        shared_ptr _next = nullptr;
        shared_ptr _prev = nullptr;

        ~listnode()
        {
            cout << "析构" << endl;
        }
    };

    shared_ptr < listnode > p1(new listnode);
    shared_ptr < listnode > p2(new listnode);
    p1->_next = p2;
    p2->_prev = p1;

智能指针

可以看到,这么本身要析构两次的,但没有释放,造成了内存泄漏

智能指针

p1指向next的空间

p2指向prev的空间

指针指针赋值

next管理着prev的值

prev也管理着next的值

这时管理next有2个 p1 和prev

这是管理prev有2个 p2和next

p1和p2释放后 next和prev还有1 所以无法释放

而shared_ptr是用计数方式。所以要释放时 管理某个地址的指针为0时,才可以释放此地址

而他们两个指针互相管理着,都在等着对方为0 造成了无法释放的问题 造成内存泄漏 这叫做循环引用问题

此时就要用到weak_ptr来辅助shared_ptr来解决

智能指针

weak_ptr的作用就是帮next和prev管理。不需要next和prev亲自去管理。

当weak_ptr帮忙管理时

这时管理next的有1个 p1

这时管理prev的有1个 p2

当p1和p2析构时,next和prev就自动释放了

weak只帮忙管理,不帮忙析构。

在不用拷贝时,就用unique_ptr,要拷贝就用shared_ptr

循环引用比较少见,遇到时,要用weak_ptr辅助帮忙。

定制删除器

可以自己写一个专门用来释放这个定制类

template<class T>
struct Deletea
{
public:
    void  operator()(T* ptr)
    {
        cout << "delete析构" << endl;
        delete[] ptr;
    }
};

template<class T>
struct Free
{
public:
    void operator()(T* ptr)
    {
        cout << "free析构" << endl;
        free(ptr);
    }
};

    struct test
    {
        ~test()
        {
            cout << "析构";
        }
        int a;
        int b;
    };

    unique_ptr> p1(new test[10]);
    unique_ptr> p2((test*)malloc(sizeof(test)*10));,free,deletea

Original: https://www.cnblogs.com/LonelyMoNan/p/16743363.html
Author: lemon-Breeze
Title: 智能指针

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/607469/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球