boost库中的智能指针解析

        shared_ptr应用于标准容器,一种是容器作为它的管理对象,如shared_ptr<list<T>>,使容器可以安全的共享,容器此时就类似于一个类型对象;一种是将shared_ptr作为容器的元素,如vector<shared_ptr<T>>,因为shared_ptr是支持拷贝语义和比较操作的,符合标准容器对元素的要求,因此可以实现在容器中安全容纳元素的指针而不是拷贝。

        值得注意的是,标准容器不能容纳auto_ptr(有转移语义),这是C++标准特别规定的。标准容器也不能容纳scoped_ptr,因为它不能拷贝和赋值。标准容器可以容纳指针,但由于容器无法自动管理指针元素,须额外用大量代码去做管理保证能够安全删除,制造了不少麻烦。

        不过存储shared_ptr就不一样了,它的效果与指针基本相同,但本身却做好了指针管理工作,因此少了对资源泄漏的担忧。下面代码示范具体的应用操作:

int main()

{

    typedef vector<shared_ptr<int>>vs;

    vs v(10);

    int i = 0;

    for (vs::iterator pos = v.begin(); pos != v.end(); ++pos)

    {

        (*pos) = make_shared<int>(++i);

        cout << *(*pos) <<", ";

    }

    cout << endl;

    shared_ptr<int> p = v[9];

    *p = 100;

    cout << *v[9] << endl;

}

        这里面有个需要注意的点是,对容器迭代器解引用得到shared_ptr,再解引用得到的才是真正的值。

        桥接模式是C++设计模式的一种,它把类的具体实现细节对用户隐藏起来,以达到类之间的最小耦合关系。具体实践中我们熟悉的名字可能是pimpl或者handle惯用法,它能够将头文件依赖性降到最低从而减少编译时间,而且还能避免使用虚函实现多态。这里不会详尽讲解这个设计模式的全部内容,以后会有文章来单独介绍,在此主要说明shared_ptr如何用于pimpl:

class sample

{

private:

    class impl;

    shared_ptr<impl>p;

public:

    sample();

    void print();

};

        在sample的cpp中完整定义impl类和其他功能:

class sample::impl      //内部类的实现

{

public:

    void print()

    {    cout << "impl print" << endl;}

};

sample::sample():p(new impl){}

void sample::print()

{p->print();}

具体的使用:

smaple s;

s.print();

        桥接模式非常的好用,能够在使用者一无所知的情况下对任意实现做需要的修改,减小了源文件之间的依赖性,带来了良好的灵活性。shared_ptr是这项功能一个很不错的实现工具,它解决了指针的共享和引用计数问题。

        讲讲shared_ptr(Y * p, D d)这个家伙。它的第一个参数自然是指针,而第二个删除器参数d则告诉shared_ptr在析构时不是使用delete来操作指针p,而是用d,即d(p).

        d既可以是一个函数对象也可以是一个函数指针,具有函数调用功能即可。但也是有要求的,它必须是可拷贝的,行为像delete那样,不允许抛出异常。

        为了匹配删除器功能,shared_ptr提供了get_deleter(shared_ptr<T>const & p)函数,可返回删除器指针。典型的使用我们可以看看下列对传统的使用struct FILE的c文件操作:

        shared_ptr<FILE> fp(fopen("./1.txt", "r"), fclose);

        当离开作用域时,shared_ptr会自动调用fclose()函数关闭文件。

        删除器可以使得我们能够自定义、扩展shared_ptr的行为,让它不仅能够管理内存资源,还成为一个“万能”的资源管理工具。

        shared_ptr<void>能够存储void*型指针,它可以指向任意类型,因此它就好比一个泛型指针容器,但同时可能会丧失原来的类型信息,虽然我们可以用static_pointer_cast<T>等转型函数恢复指针,但安全性差多了,一般不推荐。

        前面提到的删除器和shared_ptr<void>结合有比较高级的用法。存储一个空指针,可以实现退出作用域时调用任意函数,理论上可执行任意我们想做的工作:

void any_func(void * p)

{ ......;}

int main()

{

    shared_ptr<void>p((void*)0, any_func); 

}

        shared_ptr的功能已经远远超过了智能指针的范围,除了以上的用法外它还可以有,如包装成员函数、延时释放等,这里不做详尽介绍,可以在boost说明文档查询学习。

        weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的助手而不是智能指针,它并没有重载operator*和->,不能操作资源。它没有共享资源,它的构造不会引起指针引用计数的增加。同样析构时也不会导致引用计数减少,只是一个静静的观察者。

        虽然作为“弱”指针,但它可以使用一个重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源。但当expired() == true的时候,lock()函数将返回一个存储空指针的shared_ptr:

shared_ptr<int>sp(new int(10));

weak_ptr<int>wp(sp);

shared_ptr<int>sp2 = wp.lock();

        weak_ptr的一个重要用途是获得this指针的shared_ptr,使对象自己能够生产shared_ptr管理自己:在需要的时候调用lock()函数,返回一个符合要求的shared_ptr供外界使用。

        这个解决方案在头文件<boost/enable_shared_from_this.hpp>定义了一个助手类enable_shared_from_this<T>,使用的时候只需要让想被管理的类从它继承即可,成员函数shared_from_this()会返回this的shared_ptr。例如:

        需要注意的是千万不能从一个普通对象(非shared_ptr)使用shared_from_this()获取shared_ptr,因为会导致shared_ptr析构时企图删除一个栈上分配的对象,发生未定义行为。

        boost真可谓是一个宝库,尤其在思想上能够带给我们太多的启发,篇幅有限只做了较为重要的智能指针(像scoped_ptr并没提到,因为它仅在作用域可用,使用不太多)这一块介绍,其他用起来觉得不错的后续会有补充。

        更多技术交流可扫二维码或搜索关注微信公众号“嵌入式软件开发者”,我们可以在那里分享经验,共同成长!

      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值