《现代C++教程》笔记(5-7)

文章目录

  • 5 智能指针与内存管理
    • 5.1 RAII与引用计数
    • 5.2 std::shared_ptr
    • 5.3 std::unique_ptr
    • 5.4 std::weak_ptr
  • 6 正则表达式
  • 7 并行与并发
    • 7.1 并行基础
    • 7.2 互斥量与临界区
    • 7.3 期物
    • 7.4 条件变量
    • 7.5 原子操作与内存模型

5 智能指针与内存管理

5.1 RAII与引用计数

在传统 C++ 中,『记得』手动释放资源,总不是最佳实践。因为我们很有可能就忘记了去释放资源而导致泄露。 所以通常的做法是对于一个对象而言,我们在构造函数的时候申请空间,而在析构函数(在离开作用域时调用)的时候释放空间, 也就是我们常说的 RAII 资源获取即初始化技术。

凡事都有例外,我们总会有需要将对象在自由存储上分配的需求,在传统 C++ 里我们只好使用 new 和 delete 去 『记得』对资源进行释放。而 C++11 引入了智能指针的概念,使用了引用计数的想法,让程序员不再需要关心手动释放内存。 这些智能指针包括 std::shared_ptr/std::unique_ptr/std::weak_ptr,使用它们需要包含头文件 memory。

5.2 std::shared_ptr

std::shared_ptr 是一种智能指针,它能够记录多少个 shared_ptr 共同指向一个对象,从而消除显式的调用 delete,当引用计数变为零的时候就会将对象自动删除。

但还不够,因为使用 std::shared_ptr 仍然需要使用 new 来调用,这使得代码出现了某种程度上的不对称。

std::make_shared 就能够用来消除显式的使用 new,所以std::make_shared 会分配创建传入参数中的对象, 并返回这个对象类型的std::shared_ptr指针。

5.3 std::unique_ptr

std::unique_ptr 是一种独占的智能指针,它禁止其他智能指针与其共享同一个对象,从而保证代码的安全。

既然是独占,换句话说就是不可复制。但是,我们可以利用 std::move 将其转移给其他的 unique_ptr。

5.4 std::weak_ptr

std::weak_ptr是一种弱引用(相比较而言 std::shared_ptr 就是一种强引用)。弱引用不会引起引用计数增加。

std::weak_ptr 没有 * 运算符和 -> 运算符,所以不能够对资源进行操作,它可以用于检查 std::shared_ptr 是否存在,其 expired() 方法能在资源未被释放时,会返回 false,否则返回 true;除此之外,它也可以用于获取指向原始对象的 std::shared_ptr 指针,其 lock() 方法在原始对象未被释放时,返回一个指向原始对象的 std::shared_ptr 指针,进而访问原始对象的资源,否则返回nullptr。

6 正则表达式

这一章没什么好介绍的,跳过。

7 并行与并发

7.1 并行基础

std::thread 用于创建一个执行的线程实例,所以它是一切并发编程的基础,使用时需要包含 头文件, 它提供了很多基本的线程操作,例如 get_id() 来获取所创建线程的线程 ID,使用 join() 来等待一个线程结束(与该线程汇合)等等。

7.2 互斥量与临界区

我们在操作系统、亦或是数据库的相关知识中已经了解过了有关并发技术的基本知识,mutex 就是其中的核心之一。 C++11 引入了 mutex 相关的类,其所有相关的函数都放在 mutex 头文件中。

std::mutex 是 C++11 中最基本的 mutex 类,通过实例化 std::mutex 可以创建互斥量, 而通过其成员函数 lock() 可以进行上锁,unlock() 可以进行解锁。 但是在实际编写代码的过程中,最好不去直接调用成员函数, 因为调用成员函数就需要在每个临界区的出口处调用 unlock(),当然,还包括异常。 这时候 C++11 还为互斥量提供了一个 RAII 语法的模板类 std::lock_guard。 RAII 在不失代码简洁性的同时,很好的保证了代码的异常安全性。

由于 C++ 保证了所有栈对象在生命周期结束时会被销毁,所以这样的代码也是异常安全的。 无论 critical_section() 正常返回、还是在中途抛出异常,都会引发堆栈回退,也就自动调用了 unlock()。

而 std::unique_lock 则是相对于 std::lock_guard 出现的,std::unique_lock 更加灵活, std::unique_lock 的对象会以独占所有权(没有其他的 unique_lock 对象同时拥有某个 mutex 对象的所有权) 的方式管理 mutex 对象上的上锁和解锁的操作。所以在并发编程中,推荐使用 std::unique_lock。

std::lock_guard 不能显式的调用 lock 和 unlock, 而 std::unique_lock 可以在声明后的任意位置调用, 可以缩小锁的作用范围,提供更高的并发度。

如果你用到了条件变量 std::condition_variable::wait 则必须使用 std::unique_lock 作为参数。

7.3 期物

期物(Future)表现为 std::future,它提供了一个访问异步操作结果的途径,这句话很不好理解。 为了理解这个特性,我们需要先理解一下在 C++11 之前的多线程行为。

试想,如果我们的主线程 A 希望新开辟一个线程 B 去执行某个我们预期的任务,并返回我一个结果。 而这时候,线程 A 可能正在忙其他的事情,无暇顾及 B 的结果, 所以我们会很自然的希望能够在某个特定的时间获得线程 B 的结果。

在 C++11 的 std::future 被引入之前,通常的做法是: 创建一个线程 A,在线程 A 里启动任务 B,当准备完毕后发送一个事件,并将结果保存在全局变量中。 而主函数线程 A 里正在做其他的事情,当需要结果的时候,调用一个线程等待函数来获得执行的结果。

而 C++11 提供的 std::future 简化了这个流程,可以用来获取异步任务的结果。 自然地,我们很容易能够想象到把它作为一种简单的线程同步手段,即屏障(barrier)。

7.4 条件变量

条件变量 std::condition_variable 是为了解决死锁而生,当互斥操作不够用而引入的。 比如,线程可能需要等待某个条件为真才能继续执行, 而一个忙等待循环中可能会导致所有其他线程都无法进入临界区使得条件为真时,就会发生死锁。 所以,condition_variable 实例被创建出现主要就是用于唤醒等待线程从而避免死锁。 std::condition_variable的 notify_one() 用于唤醒一个线程; notify_all() 则是通知所有线程。

值得一提的是,在生产者中我们虽然可以使用 notify_one(),但实际上并不建议在此处使用, 因为在多消费者的情况下,我们的消费者实现中简单放弃了锁的持有,这使得可能让其他消费者 争夺此锁,从而更好的利用多个消费者之间的并发。话虽如此,但实际上因为 std::mutex 的排他性, 我们根本无法期待多个消费者能真正意义上的并行消费队列的中生产的内容,我们仍需要粒度更细的手段。

7.5 原子操作与内存模型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/12387.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个月学通Python(二十八):Python网络数据采集(爬虫)概述(爬虫)

专栏介绍 结合自身经验和内部资料总结的Python教程,每天3-5章,最短1个月就能全方位的完成Python的学习并进行实战开发,学完了定能成为大佬!加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础)》 文章目录 专栏介绍什么是爬虫爬虫的应用领域爬虫合法性探讨R…

Go语言中的结构体详解

关于 Golang 结构体 Golang 中没有“类”的概念,Golang 中的结构体和其他语言中的类有点相似。和其他面向对 象语言中的类相比,Golang 中的结构体具有更高的扩展性和灵活性。 Golang 中的基础数据类型可以表示一些事物的基本属性,但是当我们…

HuggingGPT Solving AI Tasks with ChatGPT and its Friends in Hugging Face

总述 HuggingGPT 让LLM发挥向路由器一样的作用,让LLM来选择调用那个专业的模型来执行任务。HuggingGPT搭建LLM和专业AI模型的桥梁。Language is a generic interface for LLMs to connect AI models 四个阶段 Task Planning: 将复杂的任务分解。但是这里…

Android.mk中的LOCAL_OVERRIDES_PACKAGES用法

Android.mk中的LOCAL_OVERRIDES_PACKAGES用法_mk local_over_觅风者的博客-CSDN博客 Android.mk中的LOCAL_OVERRIDES_PACKAGES的用法说明可以参考以下文章: Android.mk覆盖替换LOCAL_OVERRIDES_PACKAGES 此变量可以使其他的模块不加入编译 项目中遇到的问题&…

C语言复合赋值符和运算符的优先级问题

结论: 复合赋值符的优先级小于运算符 【练习1】 a * a / b的运算顺序是什么? a / b * a 【练习2】 x / 3 2 * 3 2 / 3 6 2 x 0

【力扣周赛】第 355 场周赛(构造二分答案异或前缀 状态压缩⭐)

文章目录 Q1:6921. 按分隔符拆分字符串(双指针)Q2:6915. 合并后数组中的最大元素(倒序遍历贪心)代码优化 Q3:6955. 长度递增组的最大数目🚹🚹🚹🚹…

【python】 清空socket缓冲区

在Python中使用Socket进行网络通信时,可以通过调用socket.recv()函数来接收数据,数据会被存储在缓冲区中。有时候,可能想要先清空缓冲区,以便后续的数据不会被之前的数据影响。以下是一种清空Python Socket缓冲区的方法&#xff1…

【JavaEE初阶】——第七节.Servlet入门学习笔记

作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:JavaEE进阶 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!! 文章目录 前…

【ARM 常见汇编指令学习 5 -- arm64汇编指令 wzr 和 xzr】

文章目录 ARM64 zero registerARMv8 zero 寄存器的背景xzr 在寄存器读写操作中的使用 上篇文章:ARM 常见汇编指令学习 4 – ARM64 比较指令 cbnz 与 b.ne 区别 下篇文章:ARM 常见汇编指令学习 6 - bic(位清除), orr(位或), eor(异或) ARM64 zero registe…

安全攻击 --- XSS攻击

XSS跨站脚本攻击 (1)简介 OWASP TOP 10 之一,XSS被称为跨站脚本攻击(Cross-Site-Scripting)主要基于JavaScript(JS)完成攻击行为XSS通过精心构造JS代码注入到网页中,并由浏览器解释…

【flutter】flutter如何让app内字体大小不随着系统改变而改变

如果我们不特意设置,flutter开发的app他的字体大小是会跟着系统设置的字体大小而改变,这样就会导致页面出现布局错乱问题,那么如何解决这个问题呢?我也搜索了相关资料,有两个常用也是网络上搜集到比较多的方法&#xf…

vs2013 32位 编译的 dll,重新用vs2022 64位编译,所遇问题记录

目录 一、vs2013 32 DLL 转 VS2022 64 DLL 所遇问题 1、 LNK2038: 检测到“_MSC_VER”的不匹配项: 值“1800”不匹配值“1900” 2、原先VS2013 现在 VS2022 导致的vsnprintf 重定义问题 3、 无法解析的外部符号 __vsnwprintf_s 4、无法解析的外部符号__imp__CertFreeC…

Ros终端出现找不到bash: /home/***/devel/setup.bash: 没有那个文件或目录

现象:Ros终端出现找不到bash: /home/***/devel/setup.bash: 没有那个文件或目录 问题:配置时路径写错 解决方法:改正路径 1.打开文件 gedit ~/.bashrc2.修改正确路径

【ruby on rails】M1遇到的一些安装问题

1. homebrew位置变了 原来的Cellar Homebrew Caskroom 都是在 /usr/local/下面 M1在/opt/homebrew下面 2. 装ruby M1电脑安装ruby,装不上的问题 RUBY_CFLAGS"-w" rbenv install 2.7.43. 装puma报错 gem install puma -v 5.5.2 -- --with-openssl-dir…

Kubernetes.Service—使用源 IP

使用源 IP 运行在 Kubernetes 集群中的应用程序通过 Service 抽象发现彼此并相互通信,它们也用 Service 与外部世界通信。 本文解释了发送到不同类型 Service 的数据包的源 IP 会发生什么情况,以及如何根据需要切换此行为。 准备开始 术语表 本文使用…

kotlin 编写一个简单的天气预报app(三)

使用eventbus替换broadcast 将从Broadcast切换到EventBus有以下几个好处: 解耦性:通过使用EventBus,您可以实现组件之间的解耦。传统的Broadcast机制需要发送方和接收方明确知道对方的存在,并且需要在代码中设置Intent过滤器和广…

安装Harbor

前言 Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,虽然Docker官方也提供了公共的镜像仓库,但是从安全和效率等方面考虑,部署企业内部的私有环境Registry是非常必要的,Harbor和docker中央仓库的关系,…

2023牛客多校第三场 B.Auspiciousness

传送门 前题提要:没得说,赛时根本没想到dp,赛后翻各大题解看了很久,终于懂了dp的做法,故准备写一篇题解. 首先,先定义一下我们的 d p dp dp方程,考虑将处于 [ 1 , n ] [1,n] [1,n]的数当做小数,将处于 [ n 1 , 2 ∗ n ] [n1,2*n] [n1,2∗n]的数当做大数.那么对于我们的摸牌结…

CEC2022代码(Matlab代码)及多种智能优化算法求解CEC2022

一、CEC2022测试函数 CEC2022测试集共有12个单目标测试函数,每个测试函数可选择的维度分别为10维、20维。该测试集合也是目前高质量论文应用最广泛的测试集,CEC2022测试集函数复杂,非常具有挑战力。 CEC2022测试函数与理论最优值 二、多种智…

hcip——ospf综合

要求 1. 搭建toop 2.地址规划 协议范围路由器地址 RIP 172.16.0.0 17 R12 loop0:172.16.0.0 24 loop1:172.16.1.0 24 OSPF 172.16.128.0 17 area1 172.16.144.0 20 R1 g0:172.16.144.1 24 loop0:172.16.145.1 24 R2 g0:172.16.144.2 24 loop:172…