shared_ptr

Shared_ptr使用

编写C++程序中最头疼的事情莫过于内存的管理,有时候很羡慕隔壁写C#的,只需要关心功能是否实现,当然现在也有很多C++内存泄露的检测工具,等对STL,boost有了一定的了解,要开始去了解那部分知识。
裸指针固然效率很高,但是如果不够严谨的话,容易出现问题。不好管理的地方:

  1. 创建对象,函数中有if或者switch语句,在异常处理的时候直接return,忘记释放
  2. 需要多处调用同一个对象,因为涉及多个函数,最后你已经忘记了释放。

Shared_ptr有点类似内核对象,使用引用计数,当计数为0,释放资源。以引用计数方式实现资源共享。Ok,让我们看看shared_ptr简单例子,借用网上一个小例子,忘记出处了。

class A
{
  public:
    A(int data):num(data)
    {
        cout << "get new a" << endl;
    }
    A(const A &other)
    {
        num = other.num;
        cout << "copy" << endl;
    }

    int getNum()
    {
        return num;
    }
    ~A()
    {
        cout << num << " destroy" << endl;
    }

  public:
    int num;
};
int main()
{
    boost::shared_ptr<A> data(new A(3));
    //建议使用下面这种方式
    // boost::shared_ptr<A>data=boost::make_shared<A>(3);
    cout<<data->getNum()<<endl;
    return 0;
}

输出:

get new a
3
3 destroy

使用shared_ptr,希望不再使用new,但是我们看到很奇怪的是,有一个new,delete由shared_ptr自动释放。而使用工厂方法的make_shared不再需要new,且性能更高,make_shared只需要申请一次内存,包括数据与内存控制块,而shared_ptr先申请内存,再申请控制块,见make_shared和shared_ptr的区别


实际情况中往往不是简单的一个类,比如与容器的结合。

class A_Mgr
{
  public:
    int size;
    typedef boost::shared_ptr<A> DataPtr;
    std::vector<DataPtr> vsa;

  public:
    A_Mgr()
    {
        size = 0;
    }
    ~A_Mgr()
    {
        cout << "size is:" << vsa.size() << endl;
    }

    void insert_data(int data)
    {
        vsa.push_back(boost::shared_ptr<A>(new A(data)));
    }
    void insert_data(A *data)
    {
        vsa.push_back(boost::shared_ptr<A>(data));
    }
    void insert_data(boost::shared_ptr<A> data)
    {
        cout << "before insert ,data size is" << data.use_count() << endl;
        vsa.push_back(data);
    }
    // int insert_data()
    // {
    //     // boost::shared_ptr<A> ele=make_shared<A>();
    //     vsa.push_back(boost::make_shared<A>());
    //     return size++;
    // }
    DataPtr operator[](int index)
    {
        assert(index<size);
        cout << "use count is:" << vsa[index].use_count() << endl;
        return vsa[index];
    }

    void clear()
    {
        cout << "use count is:" << vsa[0].use_count() << endl;
        size = 0;
        vsa.clear();
    }
};

以vector为例,存放share_ptr的数据,本例子中使用3种不同的方式插入数据
2)传入指针的方式,意味着,在A_Mgr外面有一个已经创建好的指针,new了对象。如果万一忘记了,我们手动使用了delete,。。。
3)直接传入shared_ptr显然也是我们不希望看到的方式,因为这种方式存入,资源在创建对象的函数中还有一个计数。

因为实际需要,重载了一个[]操作符,使用拷贝构造函数主要有这么几种方式:

  1. 函数以传值方式
  2. 函数返回值为值
  3. 以一个对象初始化另一个对象

引用计数的增加也在这3个地方,因此,这里的[]操作符返回,切记不要再用对象来接了,否则生命周期将受这个对象的生存周期影响。
顺便测试了下vector,这里的clear将会正确的释放A的内存。在使用vector,clear之后使用swap,shrink_to_fit都能够减少vector的大小。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值