zoukankan      html  css  js  c++  java
  • weak_ptr解决shared_ptr环状引用所引起的内存泄漏[转]

    转载:http://blog.csdn.net/liuzhi1218/article/details/6993135

    循环引用:

    引用计数是一种便利的内存管理机制,但它有一个很大的缺点,那就是不能管理循环引用的对象。一个简单的例子如下:

    #include<string>
    #include <iostream>
    #include <boost/shared_ptr.hpp>
    #include <boost/weak_ptr.hpp>
    
    class parent;
    class children;
    
    typedef boost::shared_ptr<parent> parent_ptr;
    typedef boost::shared_ptr<children> children_ptr;
    
    class parent
    {
    public:
        ~parent() { std::cout <<"destroying parent
    "; }
    
    public:
        children_ptr children;
    };
    
    class children
    {
    public:
        ~children() { std::cout <<"destroying children
    "; }
    
    public:
        parent_ptr parent;
    };
    
    
    void test()
    {
        parent_ptr father(new parent());
        children_ptr son(new children);
    
        father->children = son;
        son->parent = father;
    }
    
    void main()
    {
        std::cout<<"begin test...
    ";
        test();
        std::cout<<"end test.
    ";
    }
    

      

    运行该程序可以看到,即使退出了test函数后,由于parent和children对象互相引用,它们的引用计数都是1,不能自动释放,并且此时这两个对象再无法访问到。这就引起了c++中那臭名昭著的内存泄漏。

    一般来讲,解除这种循环引用有下面有三种可行的方法:

    1. 当只剩下最后一个引用的时候需要手动打破循环引用释放对象。
    2. 当parent的生存期超过children的生存期的时候,children改为使用一个普通指针指向parent。
    3. 使用弱引用的智能指针打破这种循环引用。

    虽然这三种方法都可行,但方法1和方法2都需要程序员手动控制,麻烦且容易出错。这里主要介绍一下第三种方法和boost中的弱引用的智能指针boost::weak_ptr。

    强引用和弱引用

    一个强引用当被引用的对象活着的话,这个引用也存在(就是说,当至少有一个强引用,那么这个对象就不能被释放)。boost::share_ptr就是强引用。

    相对而言,弱引用当引用的对象活着的时候不一定存在。仅仅是当它存在的时候的一个引用。弱引用并不修改该对象的引用计数,这意味这弱引用它并不对对 象的内存进行管理,在功能上类似于普通指针,然而一个比较大的区别是,弱引用能检测到所管理的对象是否已经被释放,从而避免访问非法内存。

    boost::weak_ptr

    boost::weak_ptr<T>是boost提供的一个弱引用的智能指针,它的声明可以简化如下:

    namespace boost {
    
        template<typename T>class weak_ptr {
        public:
            template <typename Y>
            weak_ptr(const shared_ptr<Y>& r);
    
            weak_ptr(const weak_ptr& r);
    
            ~weak_ptr();
    
            T* get() const; 
            bool expired() const;
            shared_ptr<T> lock() const;
        }; 
    }
    

      

    可以看到,boost::weak_ptr必须从一个boost::share_ptr或另一个boost::weak_ptr转换而来,这也说 明,进行该对象的内存管理的是那个强引用的boost::share_ptr。boost::weak_ptr只是提供了对管理对象的一个访问手段。

    boost::weak_ptr除了对所管理对象的基本访问功能(通过get()函数)外,还有两个常用的功能函数:expired()用于检测所管理的对象是否已经释放;lock()用于获取所管理的对象的强引用指针。

    通过boost::weak_ptr来打破循环引用

    由于弱引用不更改引用计数,类似普通指针,只要把循环引用的一方使用弱引用,即可解除循环引用。对于上面的那个例子来说,只要把children的定义改为如下方式,即可解除循环引用:

    class children
    {
    public:
        ~children() { std::cout <<"destroying children
    "; }
    
    public:
        boost::weak_ptr<parent> parent;
    };
    

      

    最后值得一提的是,虽然通过弱引用指针可以有效的解除循环引用,但这种方式必须在程序员能预见会出现循环引用的情况下才能使用,也可以是说这个仅仅 是一种编译期的解决方案,如果程序在运行过程中出现了循环引用,还是会造成内存泄漏的。因此,不要认为只要使用了智能指针便能杜绝内存泄漏。毕竟,对于 C++来说,由于没有垃圾回收机制,内存泄漏对每一个程序员来说都是一个非常头痛的问题。

  • 相关阅读:
    PHP调用WCF提供的方法
    关于git报 warning: LF will be replaced by CRLF in README.md.的警告的解决办法
    vue中引入mui报Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them的错误
    微信小程序报Cannot read property 'setData' of undefined的错误
    Vue那些事儿之用visual stuido code编写vue报的错误Elements in iteration expect to have 'v-bind:key' directives.
    关于xampp中无法启动mysql,Attempting to start MySQL service...的解决办法!!
    PHP的环境搭建
    新手PHP连接MySQL数据库出问题(Warning: mysqli_connect(): (HY000/1045): Access denied for user 'root'@'localhost' (using password: YES))
    手机号码、获得当前时间,下拉框,填写限制
    团队作业(五):冲刺总结
  • 原文地址:https://www.cnblogs.com/Przz/p/6657680.html
Copyright © 2011-2022 走看看