千家信息网

C语言智能指针之怎么使用weak_ptr

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这篇文章主要讲解了"C语言智能指针之怎么使用weak_ptr",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C语言智能指针之怎么使用weak_ptr"吧
千家信息网最后更新 2026年11月01日C语言智能指针之怎么使用weak_ptr

这篇文章主要讲解了"C语言智能指针之怎么使用weak_ptr",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C语言智能指针之怎么使用weak_ptr"吧!

前言

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

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

使用环境

1.VS2015 + Windows7(应该是C++11标准)

2.头文件#include

3.命名空间using namespace std;

测试过程

1.weak_ptr解决shared_ptr循环引用的问题

定义两个类,每个类中又包含一个指向对方类型的智能指针作为成员变量,然后创建对象,设置完成后查看引用计数后退出,看一下测试结果:

class CB;class CA{public:    CA() { cout << "CA() called! " << endl; }    ~CA() { cout << "~CA() called! " << endl; }    void set_ptr(shared_ptr& ptr) { m_ptr_b = ptr; }    void b_use_count() { cout << "b use count : " << m_ptr_b.use_count() << endl; }    void show() { cout << "this is class CA!" << endl; }private:    shared_ptr m_ptr_b;};class CB{public:    CB() { cout << "CB() called! " << endl; }    ~CB() { cout << "~CB() called! " << endl; }    void set_ptr(shared_ptr& ptr) { m_ptr_a = ptr; }    void a_use_count() { cout << "a use count : " << m_ptr_a.use_count() << endl; }    void show() { cout << "this is class CB!" << endl; }private:    shared_ptr m_ptr_a;};void test_refer_to_each_other(){    shared_ptr ptr_a(new CA());    shared_ptr ptr_b(new CB());    cout << "a use count : " << ptr_a.use_count() << endl;    cout << "b use count : " << ptr_b.use_count() << endl;    ptr_a->set_ptr(ptr_b);    ptr_b->set_ptr(ptr_a);    cout << "a use count : " << ptr_a.use_count() << endl;    cout << "b use count : " << ptr_b.use_count() << endl;}

测试结果如下:

CA() called!
CB() called!
a use count : 1
b use count : 1
a use count : 2
b use count : 2

通过结果可以看到,最后CA和CB的对象并没有被析构,其中的引用效果如下图所示,起初定义完ptr_a和ptr_b时,只有①③两条引用,然后调用函数set_ptr后又增加了②④两条引用,当test_refer_to_each_other这个函数返回时,对象ptr_a和ptr_b被销毁,也就是①③两条引用会被断开,但是②④两条引用依然存在,每一个的引用计数都不为0,结果就导致其指向的内部对象无法析构,造成内存泄漏。


解决这种状况的办法就是将两个类中的一个成员变量改为weak_ptr对象,因为weak_ptr不会增加引用计数,使得引用形不成环,最后就可以正常的释放内部的对象,不会造成内存泄漏,比如将CB中的成员变量改为weak_ptr对象,代码如下:

class CB{public:    CB() { cout << "CB() called! " << endl; }    ~CB() { cout << "~CB() called! " << endl; }    void set_ptr(shared_ptr& ptr) { m_ptr_a = ptr; }    void a_use_count() { cout << "a use count : " << m_ptr_a.use_count() << endl; }    void show() { cout << "this is class CB!" << endl; }private:    weak_ptr m_ptr_a;};

测试结果如下:

CA() called!CB() called!a use count : 1b use count : 1a use count : 1b use count : 2~CA() called!~CB() called!

通过这次结果可以看到,CA和CB的对象都被正常的析构了,引用关系如下图所示,流程与上一例子相似,但是不同的是④这条引用是通过weak_ptr建立的,并不会增加引用计数,也就是说CA的对象只有一个引用计数,而CB的对象只有2个引用计数,当test_refer_to_each_other这个函数返回时,对象ptr_a和ptr_b被销毁,也就是①③两条引用会被断开,此时CA对象的引用计数会减为0,对象被销毁,其内部的m_ptr_b成员变量也会被析构,导致CB对象的引用计数会减为0,对象被销毁,进而解决了引用成环的问题。


2. 测试weak_ptr对引用计数的影响

其实weak_ptr本身设计的很简单,就是为了辅助shared_ptr的,它本身不能直接定义指向原始指针的对象,只能指向shared_ptr对象,同时也不能将weak_ptr对象直接赋值给shared_ptr类型的变量,最重要的一点是赋值给它不会增加引用计数:

void test1(){    // 编译错误 // error C2665: "std::weak_ptr::weak_ptr": 3 个重载中没有一个可以转换所有参数类型    // weak_ptr ptr_1(new CA());    shared_ptr ptr_1(new CA());    cout << "ptr_1 use count : " << ptr_1.use_count() << endl; // 输出:ptr_1 use count : 1    shared_ptr ptr_2 = ptr_1;    cout << "ptr_1 use count : " << ptr_1.use_count() << endl; // 输出:ptr_1 use count : 2    cout << "ptr_2 use count : " << ptr_2.use_count() << endl; // 输出:ptr_1 use count : 2    weak_ptr wk_ptr = ptr_1;    cout << "ptr_1 use count : " << ptr_1.use_count() << endl; // 输出:ptr_1 use count : 2    cout << "ptr_2 use count : " << ptr_2.use_count() << endl; // 输出:ptr_1 use count : 2    // 编译错误    // error C2440 : "初始化": 无法从"std::weak_ptr"转换为"std::shared_ptr"    // shared_ptr ptr_3 = wk_ptr;}

测试weak_ptr常用函数的用法

weak_ptr中只有函数lock和expired两个函数比较重要,因为它本身不会增加引用计数,所以它指向的对象可能在它用的时候已经被释放了,所以在用之前需要使用expired函数来检测是否过期,然后使用lock函数来获取其对应的shared_ptr对象,然后进行后续操作:

void test2(){    shared_ptr ptr_a(new CA());     // 输出:CA() called!    shared_ptr ptr_b(new CB());     // 输出:CB() called!    cout << "ptr_a use count : " << ptr_a.use_count() << endl; // 输出:ptr_a use count : 1    cout << "ptr_b use count : " << ptr_b.use_count() << endl; // 输出:ptr_b use count : 1    weak_ptr wk_ptr_a = ptr_a;    weak_ptr wk_ptr_b = ptr_b;    if (!wk_ptr_a.expired())    {        wk_ptr_a.lock()->show();        // 输出:this is class CA!    }    if (!wk_ptr_b.expired())    {        wk_ptr_b.lock()->show();        // 输出:this is class CB!    }    // 编译错误    // 编译必须作用于相同的指针类型之间    // wk_ptr_a.swap(wk_ptr_b);         // 调用交换函数    wk_ptr_b.reset();                   // 将wk_ptr_b的指向清空    if (wk_ptr_b.expired())    {        cout << "wk_ptr_b is invalid" << endl;  // 输出:wk_ptr_b is invalid 说明改指针已经无效    }    wk_ptr_b = ptr_b;    if (!wk_ptr_b.expired())    {        wk_ptr_b.lock()->show();        // 输出:this is class CB! 调用赋值操作后,wk_ptr_b恢复有效    }    // 编译错误    // 编译必须作用于相同的指针类型之间    // wk_ptr_b = wk_ptr_a;    // 最后输出的引用计数还是1,说明之前使用weak_ptr类型赋值,不会影响引用计数    cout << "ptr_a use count : " << ptr_a.use_count() << endl; // 输出:ptr_a use count : 1    cout << "ptr_b use count : " << ptr_b.use_count() << endl; // 输出:ptr_b use count : 1}

现象分析

引用计数的出现,解决了对象独占的问题,但是也带来了循环引用的困扰,使用weak_ptr可以打破这种循环,当你理不清引用关系的时候,不妨采用文中画图的方式来理一理头绪,或许就会有眼前一亮的感觉。

总结 weak_ptr虽然是一个模板类,但是不能用来直接定义指向原始指针的对象。weak_ptr接受shared_ptr类型的变量赋值,但是反过来是行不通的,需要使用lock函数。weak_ptr设计之初就是为了服务于shared_ptr的,所以不增加引用计数就是它的核心功能。由于不知道什么之后weak_ptr所指向的对象就会被析构掉,所以使用之前请先使用expired函数检测一下。 测试源码

感谢各位的阅读,以上就是"C语言智能指针之怎么使用weak_ptr"的内容了,经过本文的学习后,相信大家对C语言智能指针之怎么使用weak_ptr这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

对象 函数 输出 指针 问题 指向 智能 类型 测试 变量 结果 编译 就是 语言 只有 成员 时候 错误 循环 两个 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 南京欣网互联网络科技有限公司 河南云网互联网络科技有限公司 盈实互联网科技 港股互联网科技股 互联网科技的英文 碳银互联网科技有限公司 金融科技和互联网金融 甘肃拓世互联网科技有限公司 玖二柒互联网科技公司待遇 互联网科技中介 银川新华互联网科技职业技术培训学校图片 广州恒生互联网科技有限 成都铂石互联网科技做什么的 互联网科技和信息 互联网科技人工智能实验室 互联网公司黑科技创始人 工业互联网等科技实现智能化赋能 互联网科技资金流入 广州互联网高科技取餐柜 科技发展第三阶段互联网时代 互联网科技公司排名 互联网 科技公司 互联网科技英文 时间互联网络科技 伴你行互联网科技有限公司 山东吉时兔互联网科技有限公司 深圳国际航运科技和互联网 互联网保险科技创业 区块链结合互联网科技 高科技和互联网的现代国家
0