c++ boost shared_ptr的使用

介绍

本文主要就是一些对boost::shared_ptr的一些翻译和个人见解,主要来源还是boost官网

share_ptr模板类储存一个动态的分配对象,一般使用c++的new表达式。这个对象的指针会在最后一次shared_ptr析构的时候或者是reset的时候删除掉。一般的用法如下:

shared_ptr<X> p1( new X );
shared_ptr<void> p2( new int(5) );

shared_ptr会删除在它构造的时候所引用的指针包括他原始的类型,无论模板参数是什么。在上面的第2个例子中,当p2析构或者reset的时候,它会删除通过构造函数生成的原始的类型的int*指针,尽管它自己的类型保存的是一个void*。

每一个shared_ptr都有一个拷贝构造,move构造,赋值或move赋值对于c++的标准库,而且可以用于c++标准库的容器。

因为使用了引用计数,所以在shared_ptr的生存周期内是不会被回收的。比如,如果main()里面有一个share_ptr指向A,直接或 者间接要回shared_ptr的指针A,A的引用计数将会是2。析构原来的shared_ptr将会使A的引用计数为1。可以使用weak_ptr破坏循环引用。循环引用是一个很难被发现,同时也是一个真实存在的问题,所以,各位在开发当中也是需要注意此点。

它的模板类型是T,对象指针的类型。shared_ptr的大部分成员函数都不依赖于T;它也允许指向不完整的类型或者是void。成员函数(构造或者重置)都可以明确的设置。

shared_ptr<T>能明确的转换成shared_ptr<U>,当T*可以明确的转换成U*时。一般 的,shared_ptr<T>可以准确的转换成shared_ptr<U>,转换成shared_ptr<U> 当U是T的可访问的基类时或者转换成shared_ptr<void>。

现在shared_ptr也是c++11的标准,如同std::shared_ptr。

从boost 1.53开始,shared_ptr就可以被动态数组使用。完全可以使用数组类型(T[] 或 T[N])作为模板参数。这基本和使用不确定的数组T[]没有任何区别,或者一个固定的数组T[N];然后可以使用[]操作符去核实索引的范围。比如:

shared_ptr<double[1024]> p1( new double[1024] );
shared_ptr<double[]> p2( new double[n] );

最好的实践

一个简单的减少内存泄漏的指南:经常使用智能指针去持有new的结果。每一个有new的地方都可能有这样的代码:

shared_ptr<T> p(new Y);

上面,是一个能接受使用shared_ptr的地方;T和Y有相同的类型,或者通过参数Y来构造也是同样的。

如果看到遵守这个指南,那就自然的表明你没有一个明确的删除状态;try/catch结构也是很少的了。

避免使用临时的shared_ptr,去看看为什么这样会是危险的,考虑这样的例子:

void f(shared_ptr<int>, int);
int g();
 
void ok()
{
    shared_ptr<int> p( new int(2) );
    f( p, g() );
}
 
void bad()
{
    f( shared_ptr<int>( new int(2) ), g() );
}

ok函数的方案是比较好的,反之bad函数以一个临时的shared_ptr来代替,可能导致内存泄漏。因为函数参数是未指定顺序的,可能new int(2)先,g()后,如果g函数抛出一个异常,我们无法得到shared_ptr的构造。可以看看Herb Sutter’s treatment这里关于这个问题的更多信息。

上面谈到的关于异常安全的问题可以被定义于boost/make_shared.hpp中的make_sharedallocate_shared工厂函数消息。这些工厂函数也可以提高效率对于内存分配。

个人见解

其实boost文档已经讲解的很详细,此处主要讲解shared_ptr的void模板参数和其它类型之间的转换。

编程的时候经常会用到void*来当做参数,比如函数的参数,或者是队列的消息投递时当成结构体来使用,如下:

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
 
void print(void *p)
{
     int *pt = static_cast<int*>(p);
     std::cout << *pt << std::endl;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
     int *p = new int(4);
     print(p);
     delete p;
 
    return 0;
}

当然,这是一个很 简单的例子,只是说明场景,这需要你自己去删除指针,而下面的例子则智能指针会帮你删除,不需要你负责:

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
 
typedef boost::shared_ptr<int> intPtr;
typedef boost::shared_ptr<void> voidPtr;
 
void print(voidPtr p)
{
     intPtr p1 = boost::static_pointer_cast<int>(p);
     if (!p1)
     {
         std::cout << "error" << std::endl;
         return;
     }
     std::cout << *p1 << std::endl;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    intPtr p(new int(4));
     print(p);
     intPtr p1;
     print(p1);
 
    return 0;
}

以上代码主要是讲解如何把shared_ptr<void>转化成指定类型的shared_ptr,在实际应用中只要明白原理,想必复杂也不会难到大家的。

还有一个就是在基类和派生类之间的转化:

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
 
class animal
{
public:
     virtual void eat() = 0;
     virtual void shout() = 0;
};
 
typedef boost::shared_ptr<animal> animalPtr;
 
class dog : public animal
{
public:
     virtual void eat()
     {
         std::cout << "bone" << std::endl;
     }
     virtual void shout()
     {
         std::cout << "wang wang wang" << std::endl;
     }
};
 
typedef boost::shared_ptr<dog> dogPtr;
 
class cat : public animal
{
public:
    virtual void eat()
     {
        std::cout << "fish" << std::endl;
     }
     virtual void shout()
     {
         std::cout << "miao miao miao" << std::endl;
     }
};
 
typedef boost::shared_ptr<cat> catPtr;
 
void eat(const animalPtr& ptr)
{
     ptr->eat();
}
 
void shout(const animalPtr& ptr)
{
     ptr->shout();
}
 
int _tmain(int argc, _TCHAR* argv[])
{
     dogPtr pDog(new dog);
     eat(pDog);
     shout(pDog);
     catPtr pCat(boost::make_shared<cat>());
     eat(pCat);
     shout(pCat);
 
     /// 以下演示如何把派生类转化为子类,不过一般以下转化比较少见
     animalPtr pAnimal(new dog);
     pDog = boost::dynamic_pointer_cast<dog>(pAnimal);
     if (!pDog)
    {
         std::cout << "failed" << std::endl;
         return 1;
     }
     std::cout << "success" << std::endl;
 
 
     return 0;
}

以上算是以代码的方式诠释了boost文档当中的一些说明和用法。并适当增加了一些个人的见解。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Z小偉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值