浅谈RAII和智能指针 | Blurred code

浅谈RAII和智能指针

panda

2019/03/02

LastMod:2021/02/23

Categories: cpp

不管cpp有多少被诟病的地方,但是RAII是一个很伟大的发明。可以说不懂RAII,连C++的门槛都还没入。 《cpp primer》在第12章的动态内存中讲解了很多智能指针的使用,参考着另外一本国内的《C++泛型》的教材书上的代码,记个笔记。

RAII

RAII(Resource Acquisition is Initialization)就是把资源(内存,文件,socket)等等和一个对象的生命周期绑定起来,当对象的生命周期到的时候,自动释放资源,避免手动new/delete管理内存。 在CPP的实现中,是讲裸指针以及指针的操作封装成一个类,通过类的生命周期管理来控制资源的释放。下面列出最简单的一个管理资源的模版

template <typename T>
class My_ptr
{
private:
    T *_ptr;
public:
    My_ptr(T *p):_ptr(p)
    {
        std::cout<<"Wrapped"<<std::endl;
    }

    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
    ~My_ptr()
    {
        std::cout<<"Released"<<std::endl;
        delete _ptr;
    }
};

它将裸指针封装起来,封装在一个类里,类销毁了,资源也就释放了。这样避免了手动delete的操作。

Shared_ptr

Shared_ptr在最原始的封装上更进一步,加入了引用计数。先定义一个资源的拥有者Res_ptr,它拥有资源和计数器,不对外暴露接口,定义一个友元类Shared_ptr,它通过Res_ptr访问资源,同时具有复制,拷贝构造函数来增加计数。

template <typename T> class Shared_ptr;
template <typename T> class Res_ptr;
template <typename T>
class Res_ptr
{
private:
    T* res_ptr;
    int count;
    Res_ptr(T* p):res_ptr(p),count(1){}
    ~Res_ptr()
    {
        delete res_ptr;
        std::cout<<"resource released"<<std::endl;
    }
   friend class Shared_ptr<T>;
};
template <typename T>
class Shared_ptr
{
private:
    Res_ptr<T>* ptr;
public:
    T& operator*()
    {
        return *(ptr->res_ptr);
    }
    T* operator->()
    {
        return ptr->res_ptr;
    }
    Shared_ptr(T* p):ptr(new Res_ptr<T>(p))
    {
        std::cout<<"Shared_ptr constructor"<<"\t"<<"count="<<ptr->count<<std::endl;
    }
    Shared_ptr(const Shared_ptr& sp):ptr(sp.ptr)
    {
        ++ptr->count;
        std::cout<<"Shared_ptr copy  constructor"<<"\t"<<"count="<<ptr->count<<std::endl;
    }

    ~Shared_ptr()
    {
        std::cout<<"Shared_ptr deconstructor"<<"\t"<<"count="<<ptr->count<<std::endl;
        if(--ptr->count==0)
            delete ptr;
    }

};


template <typename T>
Shared_ptr<T> make_shared(T&& ts)
{
    return Shared_ptr<T>(new T(std::forward<T>(ts)));
}

int main()
{

    {
        auto p1 = ptr::make_shared<int>(1);
        *p1 = 200;
        {
            auto p2 = p1;
            auto p3 = p1;
            auto p4 = p1;
        }
        std::cout<<*p1<<std::endl;
    }
    return 0;
}

输出结果如下

Shared_ptr constructor  count=1
Shared_ptr copy  constructor    count=2
Shared_ptr copy  constructor    count=3
Shared_ptr copy  constructor    count=4
Shared_ptr deconstructor        count=4
Shared_ptr deconstructor        count=3
Shared_ptr deconstructor        count=2
200
Shared_ptr deconstructor        count=1
resource released