C++ shared_ptr

        std:: shared_ptr 属于STL库,它的作用和auto_ptr相似,也是管理一个对象指针,提供一个释放内存的封装操作,但是它可以和其他shared_ptr对象共享对指针的管理。
它的实现原理是再内部维护一个引用计数,当引用计数为0的时候进行释放销毁操作。
        std::shared_ptr的构造函数有多重,我们常用的是默认构造函数和带有指针参数的构造函数:
        
default (1)
constexpr shared_ptr() noexcept;
from pointer (3)
template <class U> explicit shared_ptr (U* p);
默认的构造函数初始化引用为0,带有指针参数的构造函数初始化引用为1。另外拷贝构造函数:
copy (6)
shared_ptr (const shared_ptr& x) noexcept;
template <class U> shared_ptr (const shared_ptr<U>& x) noexcept;
如果x不为空,那么引用计数在x的基础上加1。如果x为空,那么本次构造为默认构造,引用计数为0:
    std::shared_ptr<int> pTest; //默认构造.
    std::shared_ptr<int> pTest2(nullptr); //默认构造
    std::shared_ptr<int> pTest3(pTest);   //默认构造

    std::shared_ptr<int> pTest4(new int(10)); //引用为1
    std::shared_ptr<int> pTest5(pTest4);      //引用为2

        std::shared_ptr在操作符=的实现中同样会对引用计数进行操作,原理和构造函数差不多。
        到这里我们已经可以清楚地知道std::shared_ptr可以共享所有权,并且用引用计数来进行管理,当引用计数为0的时候才会进行释放操作,那么就可能造成一种引用环路问题,我们用一个网上的例子( http://blog.csdn.net/shanno/article/details/7363480 ):

#include <iostream>
#include <memory>

class Woman;
class Man 
{
private:
    std::weak_ptr<Woman> _wife;
    //std::shared_ptr<Woman> _wife;
public:
    void setWife(std::shared_ptr<Woman> woman)
    {
        _wife = woman;
    }

    void doSomthing()
    {
        if (_wife.lock())
        {
        }
    }

    ~Man() 
    {
        std::cout << "kill man\n";
    }
};

class Woman
{
private:
    //std::weak_ptr<Man> _husband;
    std::shared_ptr<Man> _husband;
public:
    void setHusband(std::shared_ptr<Man> man) 
    {
        _husband = man;
    }
    ~Woman() {
        std::cout << "kill woman\n";
    }
};


int main(int argc, char** argv) 
{
    std::shared_ptr<Man> m(new Man());
    std::shared_ptr<Woman> w(new Woman());
    if (m && w) 
    {
        m->setWife(w);
        w->setHusband(m);
    }
    return 0;
}

        在Man类内部会引用一个Woman,Woman类内部也引用一个Man。当一个man和一个woman是夫妻的时候,他们直接就存在了相互引用问题。man内部有个用于管理wife生命期的shared_ptr变量,也就是说wife必定是在husband去世之后才能去世。同样的,woman内部也有一个管理husband生命期的shared_ptr变量,也就是说husband必须在wife去世之后才能去世。这就是循环引用存在的问题:husband的生命期由wife的生命期决定,wife的生命期由husband的生命期决定,最后两人都死不掉,违反了自然规律,导致了内存泄漏。
        要解决这个问题我们就需要认识std::weak_ptr。std::weak_ptr同样是一种智能指针,但是是为了配合shared_ptr工作而存在的。它可以从一个shared_ptr或者weak_ptr中来构造,但是并不会改变引用计数
  
default (1)
constexpr weak_ptr() noexcept;
copy (2)
weak_ptr (const weak_ptr& x) noexcept;
template <class U> weak_ptr (const weak_ptr<U>& x) noexcept;
from shared_ptr (3)
template <class U> weak_ptr (const shared_ptr<U>& x) noexcept;
它比较重要的成员函数是expired和lock。expired是用来检查从属的shared_ptr是否已经析构(删除empty),lock是在expired返回值为true(从属的shared_ptr没有被删除)的情况下,返回一个从事的shared_ptr临时对象,这个临时对象的产生同样会使原来的shared_ptr引用计数增加,所以我们在实际操作中一定要控制这个临时产生的shared_ptr的生命周期。
        我们如果用weak_ptr来解决上述问题就比较简单了,在环路引用中改变一个引用为weak_ptr,不增加引用计数,在使用的时候仅仅临时产生一个shared_ptr对象来进行操作,当然如果在这个临时对象的声明周期没有销毁前原来的shared_ptr销毁了,那么管理的指针会延迟到这个临时shared_ptr销毁的时候销毁。
        和std::shared_ptr相关的比较常用的方法有:
        std::shared_ptr<int> pTest6 = std::make_shared<int>(new int());
        std::shared_ptr<A> pFather = std::dynamic_pointer_cast<B>(pChild);//static_pointer_cast const_point_cast形式差不多。

        std::shared_ptr更方便地管理内存,我们不需要再考虑析构时的顺序问题了,完全交给智能指针来管理,大大减少了程序猿的负担,减少bug的产生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值