c++智能指针之weak_ptr

介绍

weak_ptr这个指针天生一副“小弟”的模样,也是在C++11的时候引入的标准库,它的出现完全是为了弥补它老大shared_ptr天生有缺陷的问题,其实相比于上一代的智能指针auto_ptr来说,新进老大shared_ptr可以说近乎完美,但是通过引用计数实现的它,虽然解决了指针独占的问题,但也引来了引用成环的问题,这种问题靠它自己是没办法解决的,所以在C++11的时候将shared_ptrweak_ptr一起引入了标准库,用来解决循环引用的问题。

weak_ptr本身也是一个模板类,但是不能直接用它来定义一个智能指针的对象,只能配合shared_ptr来使用,可以将shared_ptr的对象赋值给weak_ptr,并且这样并不会改变引用计数的值。查看weak_ptr的代码时发现,它主要有lockswapresetexpiredoperator=use_count几个函数,与shared_ptr相比多了lockexpired函数,但是却少了get函数,甚至连operator*operator->都没有,可用的函数数量少的可怜,下面通过一些例子来了解一下weak_ptr的具体用法。

代码验证如下:

#include <iostream>
#include <memory> //auto_ptr 的头文件
#include <string>
using namespace std;


class ptrTest
{
public:
    ptrTest(int i) {
        index = i;
        cout << "ptrTest():"<<i<<endl;
    };
    ~ptrTest() {
        cout << "delete ptrTest:" << index << endl;
    };
public:
    int getIndex() {
        return index;
    };
private:
    int index = 0;
};

void main() {
    {
        shared_ptr<ptrTest> ptr_a(new ptrTest(1));
        shared_ptr<ptrTest> ptr_b(new ptrTest(2));

        cout << "ptr_a use_count:" << ptr_a.use_count()<<endl;
        cout << "ptr_b use_count:" << ptr_b.use_count() << endl;

        weak_ptr<ptrTest> wptr_a = ptr_a;
        shared_ptr<ptrTest> ptr_c = ptr_b;

        cout << "wptr_a use_count:" << ptr_a.use_count() << endl;
        cout << "ptr_c use_count:" << ptr_b.use_count() << endl;
    }
    system("pause");
}

运行结果:
在这里插入图片描述

weak_ptr智能指针使用如下

#include <iostream>
#include <memory> //auto_ptr 的头文件
#include <string>
using namespace std;

class ptrTest
{
public:
    ptrTest(int i) {
        index = i;
        cout << "ptrTest():"<<i<<endl;
    };
    ~ptrTest() {
        cout << "delete ptrTest:" << index << endl;
    };
public:
    int getIndex() {
        return index;
    };
private:
    int index = 0;
};

void main() {
    {
        //
        shared_ptr<ptrTest> ptr_a(new ptrTest(1));
        shared_ptr<ptrTest> ptr_b(new ptrTest(2));

        cout << "ptr_a use_count:" << ptr_a.use_count() << endl;
        cout << "ptr_b use_count:" << ptr_b.use_count() << endl;

        weak_ptr<ptrTest> wptr_a = ptr_a;
        shared_ptr<ptrTest> ptr_c = ptr_b;

        cout << "wptr_a use_count:" << ptr_a.use_count() << endl;
        cout << "ptr_c use_count:" << ptr_b.use_count() << endl;

        if (!wptr_a.expired())
        {
            shared_ptr<ptrTest> ptr_d = wptr_a.lock();
            cout << "wptr_a lock use_count:" << wptr_a.use_count() << endl;
        }
    }
    system("pause");
}

运行结果:

在这里插入图片描述

循环引用

weak_ptr可以解决shared_ptr循环引用问题,导致内存泄漏问题,问题模型如下图:

这里写图片描述

当shared_ptr类型的spA、spB对象析构时,ref_count 减一;由于Obj A 和 Obj B中的shared_ptr智能指针还相互引用,导致ref_count不为零,spA和spB不会去析构所指的对象,最终导致内存泄漏。

当Obj A 和 Obj B中的智能指针是weak_ptr是,不会影响share_ptr智能指针引用计数,当spA和spB析构时,导致ref_count为零,同时所指向的对象也就被析构了;其解决方案模型如下:
这里写图片描述

代码实例如下:

//strong reference
class B;
class A
{
public:
    shared_ptr<class B> m_spB;
};


class B
{
public:
    shared_ptr<class A> m_spA;
};

//weak reference
class WeakB;
class WeakA
{
public:
    weak_ptr<class WeakB> m_wpB;
};


class WeakB
{
public:
    weak_ptr<class WeakA> m_wpA;
};


void test_loop_ref()
{
    weak_ptr<class A> wp1;

    {
        auto pA = make_shared<class A>();
        auto pB = make_shared<class B>();

        pA->m_spB = pB;
        pB->m_spA = pA;

        wp1 = pA;    
    }//内存泄漏

    cout << "wp1 reference number: " << wp1.use_count() << "\n";

    weak_ptr<class WeakA> wp2;
    {
        auto pA = make_shared<class WeakA>();
        auto pB = make_shared<class WeakB>();

        pA->m_wpB = pB;
        pB->m_wpA = pA;

        wp2 = pA;
    }//无内存泄漏

    cout << "wp2 reference number: " << wp2.use_count() << "\n";
}

int main()
{    
    //std::weak_ptr 用来避免 std::shared_ptr 的循环引用
    test_loop_ref();

    return 0;
}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768

wp1和wp2作为shared_ptr智能指针的核查器,其检测结果如下:

wp1 reference number: 1//内存泄漏
wp2 reference number: 0//问题解决
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值