zoukankan      html  css  js  c++  java
  • 智能指针循环引用--转

    智能指针

      在智能指针中shared_ptr用来计算指向对象的指针的个数,但是如果先执行shared_ptr1=shared_ptr2,再执行shared_ptr2=shared_ptr1,这样shared_ptr1.count()和shared_ptr2.count()都为1,这就造成了循环引用,循环引用会导致堆内存无法正确释放,导致内存泄露。

      考虑一个简单的对象——家长与子女:a Parent has a Child,a Child Knows his parent。在C++中,如果使用原始指针作为成员,Child和Parent由谁释放?如何保证指针的有效性?如何防止出现悬空指针?这里就需要利用智能指针去实现,智能指针可以将对象语义转变为值语义,shared_ptr能轻松的解决生命周期的问题,不必担心悬空指针。但是这个模型存在循环引用的问题,就需要利用weak_ptr。

    原始指针的做法(容易出错):

    #include<bits/stdc++.h>
    using namespace std;
    
    class Parent;
    class Child;
    
    class Parent{
    private:
        Child* myChild;
    public:
        void setChild(Child* ch){
            this->myChild=ch;
        }
        void dosomething(){
            if(this->myChild){
                cout<<"Parent"<<endl;
            }
        }
        ~Parent(){
            delete myChild;
        }
    };
    
    class Child{
    private:
        Parent* myParent;
    public:
        void setParent(Parent* p){
            this->myParent=p;
        }
        void dosomething(){
            if(this->myParent){
                cout<<"Child"<<endl;
            }
        }
        ~Child(){
            delete myParent;
        }
    };
    
    int main(){
    
        {
            Parent *p=new Parent;
            Child *c=new Child;
            p->setChild(c);
            c->setParent(p);
            p->dosomething();   //Parent
            c->dosomething();   //Child
            delete c; //仅删除这一个
    //        p->dosomething(); 不能访问
        }
        return 0;
    }

    循环引用内存泄露的写法:

    #include<bits/stdc++.h>
    using namespace std;
    
    class Parent;
    class Child;
    
    class Parent{
    private:
        shared_ptr<Child> myChild;
    public:
        void setChild(shared_ptr<Child> ch){
            this->myChild=ch;
        }
        void dosomething(){
            if(this->myChild.use_count()){
                cout<<"Parent"<<endl;
            }
        }
        ~Parent(){
        }
    };
    
    class Child{
    private:
        shared_ptr<Parent> myParent;
    public:
        void setParent(shared_ptr<Parent> p){
            this->myParent=p;
        }
        void dosomething(){
            if(this->myParent.use_count()){
                cout<<"Child"<<endl;
            }
        }
        ~Child(){
        }
    };
    
    int main(){
        weak_ptr<Parent> wpp;
        weak_ptr<Child> wpc;
        {
            shared_ptr<Parent> p(new Parent);
            shared_ptr<Child> c(new Child);
            p->setChild(c);
         cout<<p.use_count()<<endl;//1
         cout<<c.use_count()<<endl;//2 c
    ->setParent(p); cout<<p.use_count()<<endl;//2 cout<<c.use_count()<<endl;//2 wpp=p; wpc=c; } //超出该域,p、c都已被析构,但是weak_ptr显示p、c的引用都为1 cout<<wpp.use_count()<<endl;//1 cout<<wpc.use_count()<<endl;//1 return 0; }

    正确做法是:

    #include<bits/stdc++.h>
    using namespace std;
    
    class Parent;
    class Child;
    
    class Parent{
    private:
        weak_ptr<Child> myChild;
    public:
        void setChild(shared_ptr<Child> ch){
            this->myChild=ch;
        }
        void dosomething(){
            if(this->myChild.lock()){
                cout<<"Parent"<<endl;
            }
        }
        ~Parent(){
        }
    };
    
    class Child{
    private:
        shared_ptr<Parent> myParent;
    public:
        void setParent(shared_ptr<Parent> p){
            this->myParent=p;
        }
        void dosomething(){
            if(this->myParent.use_count()){
                cout<<"Child"<<endl;
            }
        }
        ~Child(){
        }
    };
    
    int main(){
        weak_ptr<Parent> wpp;
        weak_ptr<Child> wpc;
        {
            shared_ptr<Parent> p(new Parent);
            shared_ptr<Child> c(new Child);
            p->setChild(c);
            cout<<p.use_count()<<endl;//1
            cout<<c.use_count()<<endl;//1
            c->setParent(p);
            cout<<p.use_count()<<endl;//2
            cout<<c.use_count()<<endl;//1
            wpp=p;
            wpc=c;
        }
    
        cout<<wpp.use_count()<<endl;//0
        cout<<wpc.use_count()<<endl;//0
        return 0;
    }

      下面是一个简单智能指针的demo。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。智能指针就是模拟指针动作的类。所有的智能指针都会重载 -> 和 * 操作符。智能指针还有许多其他功能,比较有用的是自动销毁。这主要是利用栈对象的有限作用域以及临时对象(有限作用域实现)析构函数释放内存。

    #include<bits/stdc++.h>
    using namespace std;
    
    template<typename T>
    class smartPointer{
    private:
        T* _ptr;
        size_t* _count;
    public:
        smartPointer(T* ptr=nullptr):_ptr(ptr){//构造函数
            if(_ptr){
                _count=new size_t(1);
            }
            else{
                _count=new size_t(0);
            }
        }
    
        smartPointer(const smartPointer& ptr){//拷贝构造函数
            if(this !=&ptr){
                this->_ptr=ptr._ptr;
                this->_count=ptr._count;
                (*this->_count)++;
            }
        }
    
        smartPointer& operator =(const smartPointer& ptr){//赋值构造函数
            if (this->_ptr == ptr._ptr) {
                return *this;
            }
    
            if(this->_ptr){
                (*this->_count)--;
                if(*this->_count==0){
                    delete this->_ptr;
                    delete this->_count;
                }
            }
    
            this->_ptr=ptr._ptr;
            this->_count=ptr._count;
            (*this->_count)++;
            return *this;
        }
    
        T& operator *(){//重载操作符
            assert(this->_ptr==nullptr);
            return this->_ptr;
        }
    
        T& operator->(){//重载操作符
            assert(this->_ptr==nullptr);
            return this->_ptr;
        }
    
        ~smartPointer(){//析构函数
            (*this->_count)--;
            if(*this->_count==0){
                delete this->_ptr;
                delete this->_count;
            }
        }
    
        size_t use_count(){
            return *this->_count;
        }
    };
    
    int main()
    {
        {
            smartPointer<int> sp(new int(10));
            smartPointer<int> sp2(sp);
            smartPointer<int> sp3(new int(20));
            sp=sp3;
            cout<<sp.use_count()<<endl;//1
            cout<<sp2.use_count()<<endl;//2
            cout<<sp3.use_count()<<endl;//2
        }
        {
            shared_ptr<int> sp(new int(10));
            shared_ptr<int> sp2(sp);
            shared_ptr<int> sp3(new int(20));
            sp=sp3;
            cout<<sp.use_count()<<endl;//1
            cout<<sp2.use_count()<<endl;//2
            cout<<sp3.use_count()<<endl;//2
        }
        return 0;
    }

     参考地址:https://www.cnblogs.com/wxquare/p/4759020.html、《C++ primer》

  • 相关阅读:
    Python系列:5- Day1
    Python系列:4-计算机中的进制和编码
    操作系统随笔:什么是微内核和宏内核?【华为鸿鹄操作系统-微内核】
    Python系列:3-操作系统简史
    Python系列:2-电脑结构和CPU、内存、硬盘三者之间的关系
    数据结构中头结点和头指针那么易混淆吗
    pareto最优解(多目标智能算法要用到)
    Matlab学习中遇到的不熟悉的函数(智能算法学习第一天)
    6-2
    6-1
  • 原文地址:https://www.cnblogs.com/ybf-yyj/p/9661988.html
Copyright © 2011-2022 走看看