C++11新特性之智能指针

本文章参考https://www.cnblogs.com/feng-sc/p/5710724.html#title33。因为其对智能指针介绍的比较详细,在自己的工作中,智能指针用的少,都是new delete用的多,实际开发中,不少情况下会出现内存泄漏的问题,都是因为只有new 没有delete导致的。智能指针为我们解决了资源管理的问题,让我们不再担心资源泄漏的问题。但是智能指针难道就不会存在资源泄漏的问题吗 ? 答案是NO,在用shared_ptr的时候,如果出现相互引用的情况下,shared_ptr就不能释放资源。
智能指针只是用对象去管理一个资源指针,同时用一个计数器计算当前指针引用对象的个数,当管理指针的对象增加或减少时,计数器也相应加1或减1,当最后一个指针管理对象销毁时,计数器为1,此时在销毁指针管理对象的同时,也把指针管理对象所管理的指针进行delete操作。
下面是shared_ptr的程序demo。

#include <memory>

class Person
{
public:
    Person()
    {
        cout << "Person default constructor" << endl;
    }
    ~Person()
    {
        std::cout << "~Person destructor" << endl;
    }
};

int main(int argc, char** argv)
{
    shared_ptr<Person> p1 = make_shared<Person>();
    cout << "p 1 ref count:" << p1.use_count() << endl;
    {
        std::shared_ptr<Person> p2 = p1;
        std::cout << "p 2 ref count:" << p1.use_count() << std::endl;
    }
    std::cout << "p 3 ref count:" << p1.use_count() << std::endl;

    return 0;
}

运行结果:
这里写图片描述
从上面的代码中,可知:
1、std::make_shared封装了new方法,boost::make_shared之前的原则是既然释放资源delete由智能指针负责,那么应该把new封装起来,否则会让人觉得自己调用了new,但没有调用delete,似乎与谁申请,谁释放的原则不符。C++也沿用了这一做法。

2、随着引用对象的增加std::shared_ptr p2 = p1,指针的引用计数有1变为2,当p2退出作用域后,p1的引用计数变回1,当main函数退出后,p1离开main函数的作用域,此时p1被销毁,当p1销毁时,检测到引用计数已经为1,就会在p1的析构函数中调用delete之前std::make_shared创建的指针。

下面展示shared_ptr相互引用会导致什么样的后果 ?
先看示例代码:

class TestB;
class TestA
{
public:
    TestA()
    {
        std::cout << "TestA()" << std::endl;
    }
    void ReferTestB(std::shared_ptr<TestB> test_ptr)
    {
        m_TestB_Ptr = test_ptr;
    }
    ~TestA()
    {
        std::cout << "~TestA()" << std::endl;
    }
private:
    std::shared_ptr<TestB> m_TestB_Ptr; //TestB的智能指针
};

class TestB
{
public:
    TestB()
    {
        std::cout << "TestB()" << std::endl;
    }

    void ReferTestB(std::shared_ptr<TestA> test_ptr)
    {
        m_TestA_Ptr = test_ptr;
    }
    ~TestB()
    {
        std::cout << "~TestB()" << std::endl;
    }
    std::shared_ptr<TestA> m_TestA_Ptr; //TestA的智能指针
};


int main(int argc, char** argv)
{
    shared_ptr<TestA> ptr_a = make_shared<TestA>();
    shared_ptr<TestB> ptr_b = make_shared<TestB>();
    ptr_a->ReferTestB(ptr_b);
    ptr_b->ReferTestB(ptr_a);

    return 0;
}

运行结果如下:
这里写图片描述
只看到TestA和TestB的构造函数被调用了,没看到析构函数被调用。在main即将退出之时,ptr_a和ptr_b的引用计数都是2,因此析构函数不会被调用。智能指针ptr_a中引用了ptr_b,同样ptr_b中也引用了ptr_a,在main函数退出前,ptr_a和ptr_b的引用计数均为2,退出main函数后,引用计数均变为1,也就是相互引用。
ptr_a对ptr_b说,哎,我说ptr_b,我现在的条件是,你先释放我,我才能释放你,这是天生的,造物者决定的,改不了。ptr_b也对ptr_a说,我的条件也是一样,你先释放我,我才能释放你,怎么办?是吧,大家都没错,相互引用导致的问题就是释放条件的冲突,最终也可能导致内存泄漏。该怎么办呢 ?
此时weak_ptr就该上场了。weak_ptr相互引用不会导致引用计数增加。

class TestB;
class TestA
{
public:
    TestA()
    {
        std::cout << "TestA()" << std::endl;
    }
    void ReferTestB(std::shared_ptr<TestB> test_ptr)
    {
        m_TestB_Ptr = test_ptr;
    }
    ~TestA()
    {
        std::cout << "~TestA()" << std::endl;
    }
private:
    weak_ptr<TestB> m_TestB_Ptr; //TestB的智能指针
};

class TestB
{
public:
    TestB()
    {
        std::cout << "TestB()" << std::endl;
    }

    void ReferTestB(std::shared_ptr<TestA> test_ptr)
    {
        m_TestA_Ptr = test_ptr;
    }
    ~TestB()
    {
        std::cout << "~TestB()" << std::endl;
    }
    weak_ptr<TestA> m_TestA_Ptr; //TestA的智能指针
};

把成员变量改成weak_ptr类型的,main函数不用变,那让我们再看看运行结果。
这里写图片描述
由以上代码运行结果我们可以看到:

 1、所有的对象最后都能正常释放,不会存在上一个例子中的内存没有释放的问题。

 2、ptr_a 和ptr_b在main函数中退出前,引用计数均为1,也就是说,在TestA和TestB中对std::weak_ptr的相互引用,不会导致计数的增加。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值