一:背景

上一篇我们聊到了C++ 的 auto_ptr ,有朋友说已经在 C++ 17 中被弃用了,感谢朋友提醒,今天我们来聊一下 C++ 11 中引入的几个智能指针。

  1. unique_ptr

  2. shared_ptr

  3. weak_ptr

看看它们都怎么玩。

二:三大智能指针详解

1. unique_ptr

上一篇在说 auto_ptr 的时候聊过一个术语叫 控制权转移,言外之意就是下面的代码会 访问违例 。


void test() {
int* i = new int(10); auto_ptr<int> ptr1(i);
auto_ptr<int> ptr2 = ptr1; //将 ptr1 的控制台送给了 ptr2 cout << *ptr1 << endl;
} int main() {
test();
}

这段代码用了赋值运算符,可能是程序员的无心之举,却引来程序的崩溃,那能不能规避下这种 无心 的行为呢? 当然是可以的,屏蔽掉 auto_ptr 中的赋值运算符不就可以了哈,C++ 中的 unique_ptr 就是这么实现的,可以看下源码。


class unique_ptr { public:
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
};

可以看到,unique_ptr 将 =,复制构造函数 都给屏蔽了,所以再硬写的话,必然是报错。

2. shared_ptr

这个算是纯正的 引用计数,高级语言中的 引用跟踪 经常会拿它做比较,说它存在循环引用等各种问题。

在循环引用之前,先说下它的简单用法。


void test() {
int* i = new int(10);
shared_ptr<int> ptr1(i);
shared_ptr<int> ptr2 = ptr1;
shared_ptr<int> ptr3 = ptr2; printf("ptr.refcnt= %d, ptr2.refcnt=%d, ptr3.refcnt=%d \n",
ptr1.use_count(),
ptr2.use_count(),
ptr3.use_count());
} int main() {
test();
}

再看下源码,大概在内部共同维护了对 _Ref_count_base 引用。


class _Ref_count_base {
private:
_Atomic_counter_t _Uses = 1;
_Atomic_counter_t _Weaks = 1;
}

很显然当所有的析构函数将 _Uses 降为 0 的时候就会对 i 进行释放,参考源码如下:


class shared_ptr : public _Ptr_base<_Ty> {
~shared_ptr() noexcept { // release resource
this->_Decref();
}
} class _Ref_count_base { void _Decref() noexcept { // decrement use count
if (_MT_DECR(_Uses) == 0) {
_Destroy();
_Decwref();
}
}
}

原理大概摸清楚了,接下来看下循环引用,它最大的问题就是让 _Uses 永远也不会为 0,


#include <iostream>
#include <string> using namespace std; class BClass; class AClass
{
public:
int i = 10;
shared_ptr<BClass> b;
}; class BClass
{
public:
int i = 11;
shared_ptr<AClass> a;
}; void test() { AClass* a = new AClass();
BClass* b = new BClass(); shared_ptr<AClass> aclass(a);
shared_ptr<BClass> bclass(b); aclass->b = bclass;
bclass->a = aclass; printf("a.refcnt=%d, b.refcnt=%d, a=%x,b=%x \n", aclass.use_count(), bclass.use_count(), &(*a), &(*b));
} int main() {
test();
}

接下来可以在 main 方法结束的地方观察 a,b 所有的 heap 块的内存内容是否被释放? 可以清楚的看到还在那里。。. 如下图所示:

这就是 循环引用 造成的问题,这时候就需要用到 weak_ptr 了。

3. weak_ptr

弱引用就是它的引用不改变对原对象中 _Uses 的引用,接下来将 AClass 和 BClass 中的 shared_ptr 改成 weak_ptr 版。


class AClass
{
public:
int i = 10;
weak_ptr<BClass> b;
}; class BClass
{
public:
int i = 11;
weak_ptr<AClass> a;
};

从图中可以看到,此时 refcnt=1, 再观察下地址 0x007f71a8 的内容,可以发现已经被释放啦。

好了,今天我们就聊这么多,希望对大家有帮助。

聊聊 C++ 中的几种智能指针 (下)的更多相关文章

  1. 聊聊 C++ 中的几种智能指针 (上)

    一:背景 我们知道 C++ 是手工管理内存的分配和释放,对应的操作符就是 new/delete 和 new[] / delete[], 这给了程序员极大的自由度也给了我们极高的门槛,弄不好就得内存泄露 ...

  2. c++中的四种智能指针

    c++中的四种智能指针 写惯了python,golang再来写c++总觉得头大,很大一个原因就是他没有一个GC机制. 不过c++中提供了智能指针,也不是不能用,李姐万岁! auto_ptr, shar ...

  3. c++ 中的8种智能指针[转]

    一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 ...

  4. 转载:STL四种智能指针

    转载至:https://blog.csdn.net/K346K346/article/details/81478223 STL一共给我们提供了四种智能指针: auto_ptr.unique_ptr.s ...

  5. stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结

    stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结 1. auto_ptrauto_ptr主要是用来解决资源自动释放的问题,比如如下代码:voi ...

  6. C++中的四个智能指针

    只能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象.智能指针定义在memory头文件中. 1. auto_ptr(C++11已经舍弃) 由new expression获得的对象,在au ...

  7. 聊聊 Linux 中的五种 IO 模型

    本文转载自: http://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666538919&idx=1&sn=6013c451 ...

  8. 到底有多少种智能指针(smart pointer)

    最近Qt的blog总结了到底有多少种smart pointer, 下面是一个简要的介绍: 1.   QPointer :提供对指针的保护,当一个指针被删除以后,再使用不会造成野指针或者指针溢出.比如 ...

  9. 聊聊 SpringBoot 中的两种占位符:@*@ 和 ${*}

    前言 在 SpringBoot 项目中,我们经常会使用两种占位符(有时候还会混用),它们分别是: @*@ ${*} 如果我们上网搜索「SpringBoot 的占位符 @」,大部分答案会告诉你,Spri ...

随机推荐

  1. 如何查看和修改Windows远程桌面端口

    Windows远程桌面的默认端口为3389.基于安全性考虑,部分用户有修改默认端口的需要,以减少通过远程桌面恶意攻击和扫描主机的次数. 因此今天带大家一起学习下,如何查看和修改Windows远程桌面的 ...

  2. os、json、sys、subprocess模块

    os模块 import os 1.创建目录(文件夹) os.mkdir(r'a') # 相对路径 只能创建单级目录 os.makedirs(r'a\b') # 可以创建单级和多及目录 2.删除目录 o ...

  3. 使用VUE+SpringBoot+EasyExcel 整合导入导出数据

    使用VUE+SpringBoot+EasyExcel 整合导入导出数据 创建一个普通的maven项目即可 项目目录结构 1 前端 存放在resources/static 下 index.html &l ...

  4. Vulnhub-earth

    1.信息收集 1.1找到目标主机ip vulnhub靶场通用的技巧 这里我们靶场是nat模式的 所以肯定就是在我们自己设置的一个网段范围内,我这里nat本机的地址是10.1.1.1 所处的网段就是10 ...

  5. 使用VPLS跨地域多站点建立二层交换网络

    VLL解决方案 https://www.cnblogs.com/darkchen/p/14652540.html 接上篇文档引出VPLS VLL可以跨地域建立二层交换网络,但有个缺陷是只支持两个sit ...

  6. 140_Power BI&Power Pivot之降维展示同类型比较

    博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 最近一段时间比较忙,几乎没有时间更新网站内容,今天刚好周末,更新一个简单的需求. 上效果图: 在我们日常做对比分 ...

  7. elementUI 输入框用户名和密码取消自动填充

    <!-- 用户名取消自动填充 autocomplete="off" --> <el-form-item label="用户名" prop=&q ...

  8. 20212115 实验二 《python程序设计》实验报告

    实验二 计算器设计 #20212115 2021-2022-2 <python程序设计> 实验报告二 课程: 课程:<Python程序设计>班级: 2121姓名: 朱时鸿学号: ...

  9. 关于vue项目中axios跨域的解决方法(开发环境)

    1.在config文件中修改index.js proxyTable: { "/api":{ target: 'https://www.baidu.com/muc/',//你需要跨域 ...

  10. c++(qt)播放wav文件的四种方式

    //方法一(要符合RIFF规范) 1 QSound::play("E:/Projects/报警声1-1.wav"); //方法二(要符合RIFF规范) 1 QSoundEffect ...