weak_ptr智能指针

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

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

#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()用于获取所管理的对象的强引用智能指针。spa

强引用与弱引用设计

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

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

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

若是存在,提高为shared_ptr(强引用)成功
若是不存在,提高失败

 

对于上述的例子,只须要将Parent 类里面的成员定义改成以下,便可解决循环引用问题:blog

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。

相关文章
相关标签/搜索