zoukankan      html  css  js  c++  java
  • weak_ptr<T>智能指针

      weak_ptr是为配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手,而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和operator->,它的最大作用在于协助shared_ptr,像旁观者那样观测资源的使用情况。

      但它有一个很大的缺点,那就是不能管理循环引用的对象。  

    #include <boost/shared_ptr.hpp>
    #include <iostream>
    using namespace std;
    
    class Parent;
    class Child;
    typedef boost::shared_ptr<Parent> parent_ptr;
    typedef boost::shared_ptr<Child> child_ptr;
    
    class Child
    {
    public:
        Child()
        {
            cout << "Child ..." << endl;
        }
        ~Child()
        {
            cout << "~Child ..." << endl;
        }
        parent_ptr parent_;
    };
    
    class Parent
    {
    public:
        Parent()
        {
            cout << "Parent ..." << endl;
        }
        ~Parent()
        {
            cout << "~Parent ..." << endl;
        }
        child_ptr child_;
    };
    
    int main(void)
    {
        parent_ptr parent(new Parent);
        child_ptr child(new Child);
        parent->child_ = child;
        child->parent_ = parent;
    
        return 0;
    }
     
            
     
      如上述程序的例子,运行程序可以发现Child 和 Parent 构造函数各被调用一次,但析构函数都没有被调用。由于Parent和Child对象互相引用,它们的引用计数最后都是1,不能自动释放,并且此时这两个对象再无法访问到。这就引起了内存泄漏。
     
      其中一种解决循环引用问题的办法是 手动打破循环引用,如在return 0; 之前加上一句 parent->child_.reset(); 此时
            
      当栈上智能指针对象child 析构,Child 对象引用计数为0,析构Chlid 对象,它的成员parent_ 被析构,则Parent 对象引用计数减为1,故当栈上智能指针对象parent 析构时,Parent 对象引用计数为0,被析构。
     
    但手动释放不仅麻烦而且容易出错,这里主要介绍一下弱引用智能指针 weak_ptr<T> 的用法,下面是简单的定义:
      
    amespace boost
    {
    
        template<typename T> class weak_ptr
        {
        public:
            template <typename Y>
            weak_ptr(const shared_ptr<Y> &r);
    
            weak_ptr(const weak_ptr &r);
    
            template<class Y>
            weak_ptr &operator=( weak_ptr<Y> && r );
    
            template<class Y>
            weak_ptr &operator=(shared_ptr<Y> const &r);
    
    
            ~weak_ptr();
    
            bool expired() const;
            shared_ptr<T> lock() const;
        };
    }

    两个常用的功能函数:expired()用于检测所管理的对象是否已经释放;lock()用于获取所管理的对象的强引用智能指针。

    强引用与弱引用

    强引用,只要有一个引用存在,对象就不能释放

    弱引用,并不增加对象的引用计数(实际上是不增加use_count_, 会增加weak_count_);但它能知道对象是否存在

    通过weak_ptr访问对象的成员的时候,要提升为shared_ptr

    如果存在,提升为shared_ptr(强引用)成功
    如果不存在,提升失败

    对于上述的例子,只需要将Parent 类里面的成员定义改为如下,即可解决循环引用问题:

    class Parent
    {
    public:
        boost::weak_ptr<parent> child_;
    };

          

      因为此例子涉及到循环引用,而且是类成员引用着另一个类,涉及到两种智能指针,跟踪起来难度很大,我也没什么心情像分析shared_ptr 一样画多个图来解释流程,这个例子需要解释的代码远远比shared_ptr 多,这里只是解释怎样使用

       下面再举个例子说明lock()  和 expired() 函数的用法:

        

    #include <boost/shared_ptr.hpp>
    #include <boost/weak_ptr.hpp>
    #include <boost/scoped_array.hpp>
    #include <boost/scoped_ptr.hpp>
    #include <iostream>
    using namespace std;
    
    class X
    {
    public:
        X()
        {
            cout << "X ..." << endl;
        }
        ~X()
        {
            cout << "~X ..." << endl;
        }
    
        void Fun()
        {
            cout << "Fun ..." << endl;
        }
    };
    int main(void)
    {
        boost::weak_ptr<X> p;
        boost::shared_ptr<X> p3;
        {
            boost::shared_ptr<X> p2(new X);
            cout << p2.use_count() << endl;
            p = p2;
            cout << p2.use_count() << endl;
    
            /*boost::shared_ptr<X> */
            p3 = p.lock();
            cout << p3.use_count() << endl;
            if (!p3)
                cout << "object is destroyed" << endl;
            else
                p3->Fun();
        }
        /*boost::shared_ptr<X> p4 = p.lock();
        if (!p4)
            cout<<"object is destroyed"<<endl;
        else
            p4->Fun();*/
    
        if (p.expired())
            cout << "object is destroyed" << endl;
        else
            cout << "object is alived" << endl;
    
        return 0;
    }
    

      

      从输出可以看出,当p = p2; 时并未增加use_count_,所以p2.use_count() 还是返回1,而从p 提升为 p3,增加了use_count_, p3.use_count() 返回2;出了大括号,p2 被析构,use_count_ 减为1,程序末尾结束,p3 被析构,use_count_ 减为0,X 就被析构了。

    总结:

      weak_ptr是一个“弱”指针,但它能够完成一些特殊的工作,足以证明它的存在价值。

      weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。同样,在weak_ptr析构时也不会导致引用计数的减少,它只是一个静静地观察者。

      使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count() == 0,但更快,表示观测的资源(也就是shared_ptr管理的资源)已经不复存在了。

      weak_ptr 没有重载operator*和->,这是特意的,因为它不共享指针,不能操作资源,这是它弱的原因。但它可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源。当expired() == true的时候,lock()函数将返回一个存储空指针的shared_ptr。

  • 相关阅读:
    [LiDAR数据模拟]系列(2) HELIOS的TLS点云模拟流程
    [LiDAR数据模拟]系列(1) HELIOS模拟平台介绍
    [漫谈科研]系列(1) 分享才能进步
    python消息队列snakemq使用总结
    关于modbus rtu一个主站与多个从站通信的一点总结
    关于使用ffmpeg的一些牢骚
    Pyqt5 实时图像滚动
    pyqt5 窗体布局
    PyQt5创建第一个窗体(正规套路)
    pyqt中使用matplotlib绘制动态曲线
  • 原文地址:https://www.cnblogs.com/renyuan/p/6596358.html
Copyright © 2011-2022 走看看