精华内容
下载资源
问答
  • weak_ptr--解决shared_ptr循环引用问题 我们在上篇博客讲了模拟实现三种智能指针:模拟实现三种智能指针循环引用但是我们说了,shared_ptr存在循环引用的问题。我们先介绍一下什么是shared_ptr的循环引用。我们知道...

    我们在上篇博客讲了模拟实现三种智能指针:模拟实现三种智能指针

    循环引用

    但是我们说了,shared_ptr存在循环引用的问题。我们先介绍一下什么是shared_ptr的循环引用。

    我们知道,智能指针shared_ptr采用的是引用计数的方式,下面我们来写一个双向链表。

    #include<iostream>
    #include<memory>
    using namespace std;
    
    struct Node
    {
        int _value;
        shared_ptr<Node> _next;
        shared_ptr<Node> _prev;
    };
    
    int main()
    {
        shared_ptr<Node> sp1(new Node);
        shared_ptr<Node> sp2(new Node);
    
        sp1->_next = sp2;
        sp2->_prev = sp1;
    
        cout<<sp1.use_count()<<endl; //引用计数-->2
        cout << sp2.use_count() << endl;//引用计数-->2
        system("pause");
        return 0;
    }

    上面的代码我们定义了两个块空间,我们可以 分别成它们为Node1,Node2。p1,sp2,_next,_prev均为shared_ptr类型的智能指针。sp1与sp2->prev都指向Node1,所以sp1的引用计数为2,同理sp1->_next与sp2都指向Node2,所以sp2的引用计数也为2。
    这里写图片描述

    当我们想销毁这个链表或者删除某个节点时,我们应该怎么办?
    当我们想销毁这个链表或者说销毁一个结点的时候,我们需要将引用计数置为1,假如,我们要delete sp2这块空间,我们需要将sp2的引用计数置为1,就是说我们需要将sp1->_next这个指针销毁掉。把sp2->_next销毁, 就意味着先要把sp1销毁。
    如果想把sp1销毁,就要把sp1的引用计数置为1,所以,我们就要把sp2->_prev销毁,要想把sp2->_prev销毁,就代表先要把sp2销毁。
    这样一来,我们就陷入了一个无限的循环当中。

    这就是所谓的shared_ptr智能指针的循环引用问题。

    weak_ptr

    weak_ptr是为配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。
    那我们怎么解决上面的问题呢??
    只需要把Node结点里面的指针定义为weak_ptr类型就好,weak_ptr的构造析构不会影响引用计数的大小,当我们采用这种方式时,sp1和sp2的引用计数始终为1,当我们想销毁时就可以随意操作啦。

    struct Node
    {
        int _value;
        /*shared_ptr<Node> _next;
        shared_ptr<Node> _prev;*/
    
        weak_ptr<Node> _next;
        weak_ptr<Node> _prev;
    };
    
    int main()
    {
        shared_ptr<Node> sp1(new Node);
        shared_ptr<Node> sp2(new Node);
    
        sp1->_next = sp2;
        sp2->_prev = sp1;
    
        cout<<sp1.use_count()<<endl; //引用计数-->1
        cout << sp2.use_count() << endl;//引用计数-->1
        system("pause");
        return 0;
    }
    展开全文
  • 1.3 解决类之间循环引用 1.4用 enable_shared_from_this从this转换到shared_ptr 1. 几种智能指针 1. auto_ptr: c++11中推荐不使用他(放弃) 2.shared_ptr:每添加一次引用 就+1,减少一次引用,就-1;做到指针进行...

    目录

    1. 几种智能指针

    1.1 weak_ptr

    1.2 weak_ptr基本用法

    1.3 解决类之间循环引用

    1.4 用 enable_shared_from_this从this转换到shared_ptr


    1. 几种智能指针

    1. auto_ptr: c++11中推荐不使用他(放弃)

    2. shared_ptr: 每添加一次引用 就+1,减少一次引用,就-1;做到指针进行共享

    3. unique_ptr: 一个指针同时只能有一个使用者使用

    4. weaked_ptr: 与shared_ptr搭配使用

    1.1 weak_ptr

    参考:https://zh.cppreference.com/w/cpp/memory/weak_ptr

    • std::weak_ptr 是一种智能指针,它对被 std::shared_ptr 管理的对象存在 非拥有性(“弱”)引用。在访问所引用的对象前必须 先转换为 std::shared_ptr

    • std::weak_ptr 用来 表达临时所有权的概念

      • 当某个对象只有存在时才需要被访问,而且随时可能被他人删除时,可以使用 std::weak_ptr 来跟踪该对象。

      • 需要获得临时所有权时,则将其转换为 std::shared_ptr,此时如果原来的 std::shared_ptr被销毁,则该对象的生命期将被延长至这个临时的 std::shared_ptr 同样被销毁为止。

    • std::weak_ptr 的另一用法是:打断 std::shared_ptr 所管理的对象组成的环状引用。(打破shared_ptr的循环引用)

      • 若这种环被孤立(例如无指向环中的外部共享指针),则 shared_ptr 引用计数无法抵达零,而内存被泄露。

      • 能令环中的指针之一为弱指针以避免此情况。

    循环引用的问题:该被调用的析构函数没有被调用

    #include <iostream>
    #include <memory>
    using namespace std;
     
    class Parent;
    typedef std::shared_ptr<Parent> ParentPtr;
    
    class Child
    {
    public:
        ParentPtr father;
        Child() {
            cout << "hello Child" << endl;
        }
        ~Child() {
            cout << "bye Child\n";
        }
    };
    
    typedef std::shared_ptr<Child> ChildPtr;
    
    class Parent {
    public:
        ChildPtr son;
        Parent() {
            cout << "hello parent\n";
        }
        ~Parent() {
            cout << "bye Parent\n";
        }
    };
    
    void testParentAndChild()
    {
        ParentPtr p(new Parent());
        ChildPtr c(new Child());
        p->son = c;
        c->father = p; 
    }
    
    int main()
    {
        testParentAndChild();
        return 0;
    }

    问题:c只有调用p的析构的时候,才能被释放。p只有调用c的析构的时候,才能被释放。。形成了循环引用,造成了内存泄露

    因此,引入新的智能指针,weak_ptr

    1.2 weak_ptr基本用法

    一旦外部指向shared_ptr资源失效,那么weak_ptr管理的资源自动失效 

    #include <iostream>
    #include <cassert>
    #include <memory>
    using namespace std;
     
    class Object
    {
    public:
        Object(int id) : m_id(id) {
            std::cout << "init obj " << m_id << std::endl;
        }    
        ~Object() {
            std::cout << "bye bye " << m_id << std::endl;
        }
        int id() const {
            return m_id;
        }
    private:
        int m_id;
    };
    
    
    void sharedPtrWithWeakPtr()
    {
        typedef std::shared_ptr<Object> ObjectPtr;
        typedef weak_ptr<Object> WeakObjectPtr;
        
        ObjectPtr obj(new Object(1));
        
        // 一旦外部指向shared_ptr资源失效,那么weak_ptr管理的资源自动失效 
        
        WeakObjectPtr weakObj2;           // 裸指针 
        WeakObjectPtr weakObj(obj);       // 指向shared_ptr指针 
        WeakObjectPtr weakObj3(obj);   
        cout << "obj use count is " << obj.use_count() << endl;   // 1--尽管weak_ptr也指向obj,但他只是监听者,本身并不影响引用计数次数 
        {
            // weak_ptr使用方法 
            // 外部至少还有一个shared_ptr来管理资源,同时p自己本身的资源 -- p.use_count >= 2 
            auto p = weakObj.lock();         // auto == ObjectPtr
            if (p) {
                cout << p.unique() << endl;  // 0 -- p.use_count() >= 2
            }
            else {
            }
        }
        // 不指向某份资源 
    //    obj.reset();
    //    {
    //        auto p = weakObj.lock();      // auto == ObjectPtr
    //        if (p) {
    //            assert(false);
    //        } 
    //        else {
    //            cout << "null" << endl;   // 如果调用reset,就会执行这句话 
    //        }
    //    } 
        
        // 此时, Object(1)已经失效 
        obj.reset(new Object(2)) ;
        {
            auto p = weakObj.lock();       // 返回值如果有效, 在外部必须有weakObj指向同一个资源 
            if (p) {
                assert(false);
            }
            else {
                cout << "null " << endl;   // null
            }
        }
        
        weakObj = obj;    // 又有效了 
        // 想知道weak_ptr有没有管理一份资源(外部有没有资源), 又不想生成一个shared_ptr
        if (weakObj.expired()) {
            // 资源过期了 -- true 
            cout << "no ptr" << endl;
        }
        else {
            cout << "have resource\n";
        }
    }
    
    int main()
    {
        
        sharedPtrWithWeakPtr();
        return 0;
    
    }

    1.3 解决类之间循环引用

    一旦外部指向shared_ptr资源失效,那么weak_ptr管理的资源自动失效 

    #include <iostream>
    #include <cassert>
    #include <memory>
    using namespace std;
     
    class Parent;
    typedef std::shared_ptr<Parent> ParentPtr;
    typedef std::weak_ptr<Parent> WeakParentPtr;
    
    class Child
    {
    public:
        WeakParentPtr father;                 // 只要一环换成 weak_ptr, 即可打破环 
        Child() {
            cout << "hello Child" << endl;
        }
        ~Child() {
            cout << "bye Child\n";
        }
    };
     
    typedef std::shared_ptr<Child> ChildPtr;
    typedef std::weak_ptr<Child> WeakChildPtr;
    
    class Parent {
    public:
        ChildPtr son;                 
        Parent() {
            cout << "hello parent\n";
        }
        ~Parent() {
            cout << "bye Parent\n";
        }
    };
    
    
    void testParentAndChild()
    {
        ParentPtr p(new Parent());
        ChildPtr c(new Child());
        p->son = c;            
        c->father = p;        
        cout << (c->father).use_count() << endl;
        cout << (p->son).use_count() << endl;
    }
    
    int main()
    {
        testParentAndChild();
        return 0;
    }

    析构函数成功调用, 注意析构顺序,谁是weak_ptr对象,就先析构谁。

    1.4 用 enable_shared_from_this从this转换到shared_ptr

    • 类中函数接口需要一个本对象智能指针的const引用 (如何生成本对象的智能指针)

    • 用 enable_shared_from_this从this转换到shared_ptr  (使用CRTP来使用 本对象的智能指针)

    主要代码:

    handleChildAndParent(shared_from_this(), ps);

    完整代码:

    #include <iostream>
    #include <cassert>
    #include <memory>
    using namespace std;
     
    class Parent;
    typedef std::shared_ptr<Parent> ParentPtr;
    typedef std::weak_ptr<Parent> WeakParentPtr;
     
    class Child : public std::enable_shared_from_this<Child>  // 奇异模板参数 CRTP
    {
    public:
        WeakParentPtr father;                 // 只有一环换成 weak_ptr, 即可打破环 
        Child() {
            cout << "hello Child" << endl;
        }
        ~Child() {
            cout << "bye Child\n";
        }
        void CheckRelation() {
            
        }
    };
     
    typedef std::shared_ptr<Child> ChildPtr;
    typedef std::weak_ptr<Child> WeakChildPtr;
    
    void handleChildAndParent(const ParentPtr& p, const ChildPtr& c);
    
    class Parent : public enable_shared_from_this<Parent> {
    public:
        WeakChildPtr son;                 
        Parent() {
            cout << "hello parent\n";
        }
        ~Parent() {
            cout << "bye Parent\n";
        }
        void CheckRelation() {
            auto ps = son.lock();
            if (ps) {
                //原理: 类中存在weak_ptr指针,通过一系列方式转换成 shared_ptr,然后传参 
                handleChildAndParent(shared_from_this(), ps);    // 使用CRTP来使用 本对象的指针 ★ ★ ★ ★ 
            }
            cout << "after call checkRelation\n";
        }
    };
    
    void testParentAndChild()
    {
        ParentPtr p(new Parent());
        ChildPtr c(new Child());
        p->son = c;            
        c->father = p;        
        cout << (c->father).use_count() << endl;
        cout << (p->son).use_count() << endl;
        
        p->CheckRelation();
    }
    
    void handleChildAndParentRef(const Parent& p, const Child& c)
    {
        auto cp = c.father.lock();
        auto pc = p.son.lock();
        if (cp.get() == &p && pc.get() == &c) 
        {
            cout << "right relation" << endl;
        }
        else {
            cout << "oop !!!\n";
        }
    }
    
    // const xxx&: 减少拷贝次数 
    void handleChildAndParent(const ParentPtr& p, const ChildPtr& c)
    {
        auto cp = c->father.lock();
        auto pc = p->son.lock();
        if (cp == p && pc == c)
        {
            cout << "right relation\n";
        }
        else {
            cout << "oop!!!\n";
        }
    }
    
    int main()
    {
        testParentAndChild();
        return 0;
    }

     

    展开全文
  • 使用weak_ptr打破shared_ptr循环引用

    千次阅读 2012-08-20 09:53:01
    代码示例: struct B; sruct A{  ~A() { count  boost::shared_ptr b;...// boost::shared_ptr a; // 循环引用 不可用 ... boost::weak_ptr a ; //可以打破循环引用,在先声明的B中用weak_ptr };

    代码示例:

    struct B;

    sruct A{

       ~A() { count <<" ~A()"<<endl;}

      boost::shared_ptr<B> b;

    };

     

    struct B{

      ~B() { count <<"~B()"<<endl;}

    //  boost::shared_ptr<A> a; // 循环引用 不可用

      boost::weak_ptr<A> a ; //可以打破循环引用,在先声明的B中用weak_ptr

    };

     

    int main()

    {

       boost::shared_ptr<A> ap(new A);

       boost::shared_ptr<B> bp(new B);

      ap->b = bp;

      bp->a = ap;

     return 0;

    }

     

    }

    展开全文
  • weak_ptr的构造和析构并不会改变引用计数的大小,它可以由一个shared_ptrweak_ptr的对象构造获得。它没有对“*”和“->”的重载,但可以使用lock获得一个可用的shared_ptr对象。 当面试官问到weak_

    weak_ptr 是为了辅助shared_ptr而引入的一种智能指针,它存在的意义就是协助shared_ptr更好的完成工作,我们可以把它比做成一个秘书或助理。

    weak_ptr的构造和析构并不会改变引用计数的大小,它可以由一个shared_ptr或weak_ptr的对象构造获得。它没有对“*”和“->”的重载,但可以使用lock获得一个可用的shared_ptr对象。

    当面试官问到weak_ptr智能指针的时候,你可以举出一个场景来说明它的作用

    场景--------------解决shared_ptr的循环引用问题

    我们知道,智能指针shared_ptr采用的是引用计数的方式,下面我们来写一个双向链表。

    #include<iostream>
    #include<boost/shared_ptr.hpp>
    #include<boost/weak_ptr.hpp>
    
    using namespace std;
    
    struct Node
    {
    	int _data;
    	boost::shared_ptr<Node> _next;
    	boost::shared_ptr<Node> _prev;
    };
    
    int main()
    {
    	boost::shared_ptr<Node> sp1(new Node);
    	boost::shared_ptr<Node> sp2(new Node);
    	sp1->_next = sp2;
    	sp2->_prev = sp1;
    	system("pause");
    	return 0;
    }

    我们暂且将这两块空间称为Node1,和Node2,。我们从上述代码中可知,sp1,sp2,_next,_prev均为shared_ptr类型的智能指针。sp1与sp2->prev都指向Node1,所以sp1的引用计数为2,同理sp1->_next与sp2都指向Node2,所以sp2的引用计数也为2。这是前提,注意,问题来了。




    当我们想销毁这个链表或者说销毁一个结点的时候,我们需要将引用计数置为1,假如,我们要delete sp2这块空间,我们需要将sp2的引用计数置为1,就是说我们需要将sp1->_next这个指针销毁掉。把sp2->_next销毁, 就意味着先要把sp1销毁。

    如果想把sp1销毁,就要把sp1的引用计数置为1,所以,我们就要把sp2->_prev销毁,要想把sp2->_prev销毁,就代表先要把sp2销毁。

    这样一来,我们就陷入了一个无限的循环当中。



    这就是所谓的 shared_ptr智能指针的循环引用问题。


    我们如何用weak_ptr来解决这个场景呢?

    解决:

        

    #include<iostream>
    #include<boost/shared_ptr.hpp>
    #include<boost/weak_ptr.hpp>
    
    using namespace std;
    
    struct Node
    {
    	int _data;
    	boost::weak_ptr<Node> _next;
    	boost::weak_ptr<Node> _prev;
    	//boost::shared_ptr<Node> _next;
    	//boost::shared_ptr<Node> _prev;
    };
    
    int main()
    {
    	boost::shared_ptr<Node> sp1(new Node);
    	boost::shared_ptr<Node> sp2(new Node);
    	sp1->_next = sp2;
    	sp2->_prev = sp1;
    	system("pause");
    	return 0;
    }

    只需要把Node结点里面的指针定义为weak_ptr类型就好,weak_ptr的构造析构不会影响引用计数的大小,当我们采用这种方式时,sp1和sp2的引用计数始终为1,当我们想销毁时就可以随意操作啦!

    当面试官问道你关于,shared _ptr 的循环引用问题或者weak_ptr时,你只需要将这个场景描述给他,就可以轻松的把这道题拿下了,祝你好运!

    展开全文
  • 1. 几种智能指针 1. auto_ptr: c++11中推荐不使用他(放弃) 2.shared_ptr:拥有共享对象所有权语义的智能...4.weaked_ptr:到std::shared_ptr所管理对象的弱引用 1.1 weak_ptr 参考:https://zh.cppreference.com/...
  • 智能指针循环引用: ...用weak_ptr可以打破智能指针循环引用所出现的问题。 当外部有share_ptr在管理weak_ptr资源时则该指针是有效的,否则无效用lock()来控制 如果调用reset()后再调用lock()永...
  • 上一篇文章 C++:智能指针auto_ptr, unique_ptr, shared_ptr, weak_ptr ——(1)已经介绍了auto_ptr与unique_ptr;如果有疑惑的同学可以查看; shared_ptr shared_ptr是原始指针的封装类。它是一个附加了引用计数...
  • 智能指针 1.智能指针的存在就是为了解决有时候我们申请的空间来不及释放的问题,智能指针会自己去判断是否应该释放,在这一点上比较智能,由此得名。...C++11 unique_ptr:unique_ptr将auto_ptr...
  • shared_ptrweak_ptr(解决循环引用)

    千次阅读 2018-12-13 17:47:30
    shared_ptr是带引用计数的智能指针,可以说大部分的情形选择用shared_ptr不会出问题。那么weak_ptr是什么,应该怎么用呢?  weak_ptr也是智能指针,但是比较弱,感觉没什么用。其实它的出现是伴随shared_ptr而来,...
  • C++11中常用得到智能指针为shared_ptr,它采用引用计数的方式记录当前内存资源被多少个指针使用,只有当引用计数为0时才会释放内存资源。 #include<memory> shared_ptr<int> p=make_shared<int>
  • 文章目录1、shared_ptr1.1 shared_ptr模拟2、weak_ptr3、 循环引用4、 shared_ptr删除器 1、shared_ptr  shared_ptr和uinque_ptr的最大区别是,shared_ptr可以拷贝构造和赋值,而又为了避免多个智能指针管理一个...
  • weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的 shared_ptr. weak_ptr只是提供了对管理对象的一个访问手段. weak_ptr 设计的目的是为配合...
  • Boost智能指针——weak_ptr 循环引用: 引用计数是一种便利的内存管理机制,但它有一个很大的缺点,那就是不能管理循环引用的对象。一个简单的例子如下: #include  #include  #include  #include  ...
  • 【C++】weak_ptr引用智能指针详解

    千次阅读 多人点赞 2020-05-03 15:34:11
    相比于上一代的智能指针auto_ptr来说,新进老大shared_ptr可以说近乎完美,但是通过引用计数实现的它,虽然解决了指针独占的问题,但也引来了引用成环的问题,这种问题靠它自己是没办法解决的,所以在C++11的时候将...
  • 在std::shared_ptr被引入之前,C++标准库中实现的用于管理资源的智能指针只有std::auto_ptr一个而已。std::auto_ptr的作用非常有限,因为它存在被管理资源的所有权转移问题。这导致多个std::auto_ptr类型的局部变量...
  • shared_ptr 的问题
  • http://blog.csdn.net/leichaowen/article/details/53064294
  • 转载:http://blog.csdn.net/Jacketinsysu/article/details/53341370 转载于:https://www.cnblogs.com/xuaidongstdudyrecording/p/7139469.html
  • 智能指针auto_ptr、unique_ptr、scoped_ptr、shared_ptrweak_ptr1. auto_ptr1.1 作用1.2 缺陷2. unique_ptr3. scoped_ptr4. shared_ptr 我们在写代码的时候经常会发生内存泄露情况,如忘记释放堆上指针、在释放前...
  • 智能指针在C++11版本之后提供,包含在头文件中,shared_ptr、unique_ptrweak_ptr、auto_ptr。 shared_ptr可以多个指针指向相同的对象。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。创建一个...
  • shared_ptrweak_ptr

    2021-04-06 01:14:26
    shared_ptrweak_ptr shared_ptr是带引用计数的智能指针,可以说大部分的情形选择用shared_ptr不会出问题。...同样,在weak_ptr析构时也不会导致引用计数的减少,它只是一个静静地观察者。weak_ptr没有重载operat
  • shared_ptr、unique_ptrweak_ptr,定义在memory头文件中 1. shared_ptr (1. shared_ptr类 make_shared函数 最安全的使用和分配动态内存的方法 #include <memory> shared_ptr<string> p = make_...
  • #include<iostream> #include<stdlib.h> #include<thread> #include<...//shared_ptr:功能全,支持拷贝,...设计复杂,循环引用 namespace juju { template<class T> class shared_ptr ...
  • #include #include class Woman; class Man{ ... std::weak_ptr _wife; //std::shared_ptr _wife; public: void setWife(std::shared_ptr &woman){ _wife = woman; } void doSomthing(){ if
  • stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结 stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结   1. auto_ptr auto_ptr主要是用来解决资源自动释放的问题,比如如下...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,299
精华内容 2,519
关键字:

weak_ptr循环引用