C++11新特性学习

news/2024/9/19 10:11:02/ 标签: c++, 学习, 开发语言

C++11

1. C++11新特性

  • 自动类型推导(auto)
  • 智能指针(提供更安全和更高效的内存管理)
  • 移动语义和右值引用 (move语义 &&,使得对象移动而非拷贝,在处理大量数据时提高程序性能)
  • Lambda 表达式(允许在代码中定义匿名函数对象)
  • 多线程支持(thread,mutex)
  • 增加新容器和算法

2. 智能指针

用于管理动态分配的对象的生命周期,自动释放内存,避免内存泄漏和悬挂指针等问题.

常用的智能指针有unique_ptr(独占,不能复制,只能移动)、shared_ptr(共享,多个ptr可指向同一个对象) 和 weak_ptr(用于观察)。

  • std::unique_ptr:提供对对象的唯一拥有权,具有简单的内存管理机制,支持对象的自动释放。底层使用原始指针和移动构造

    独占空间:std::unique_ptr 提供了对动态对象的唯一拥有权,确保对象在 std::unique_ptr 被销毁时自动释放内存。转移所有权:std::unique_ptr 支持通过移动构造函数和移动赋值操作符将所有权从一个 std::unique_ptr 转移到另一个,源 std::unique_ptr 被置为空。
    

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • std::shared_ptr:支持多个智能指针共享同一个对象,通过引用计数机制管理对象的生命周期。底层使用控制块来存储引用计数。

    std::shared_ptr 的引用计数机制通过控制块和两个计数器(强引用计数和弱引用计数)来管理对象的生命周期。
    强引用计数确保对象在所有 std::shared_ptr 实例销毁后才会被释放,而弱引用计数则用于 std::weak_ptr 的观察和防止循环引用。强引用计数:在 std::shared_ptr 的构造函数中初始化为 1。当一个新的 std::shared_ptr 通过复制或赋值操作创建时,强引用计数增加;当一个 std::shared_ptr 被销毁时,强引用计数减少。如果强引用计数减少到 0,对象会被销毁,控制块也会被释放(如果弱引用计数也为 0)。弱引用计数:在创建 std::shared_ptr 时,弱引用计数初始化为 0。每当一个 std::weak_ptr 创建时,弱引用计数增加;每当一个 std::weak_ptr 被销毁时,弱引用计数减少。弱引用计数用于管理 std::weak_ptr 实例,但不影响对象的生命周期。
    
  • std::weak_ptr:用于观察 std::shared_ptr 管理的对象,避免循环引用,使用锁定机制访问对象。

3. 左值引用、右值引用

  1. 左值和右值

    左值:

    • 定义:左值(Locator Value)表示内存中的一个具体位置,可以获取其地址。它是表达式中表示对象的持久性位置。
    • 特征:可以出现在赋值语句的左边,即 = 运算符的左边。
    • 示例
      int x = 10; // x 是一个左值
      x = 20; // x 依然是左值
      右值:
      
    • 定义:右值(Read Value)表示一个临时值,通常没有持久的内存位置。它通常表示一个计算结果或者常量。
    • 特征:不能出现在赋值语句的左边,即 = 运算符的右边。右值通常是临时的,不可以取得地址。
    • 示例
      int x = 10; // 10 是一个右值
      x = x + 5; // x + 5 是一个右值
      
  2. 左值引用和右值引用

    左值引用:

    • 定义:左值引用是传统的引用类型,用于绑定左值。
    • 语法:使用 T&
    • 特征:可以绑定到左值,但不能绑定到右值。
    • 示例
      int x = 10;
      int& ref = x; // ref 是一个左值引用,绑定到 x  
      右值引用:
      
    • 定义:右值引用是 C++11 引入的引用类型,用于绑定右值。
    • 语法:使用 T&&
    • 特征:可以绑定到右值,但不能绑定到左值。主要用于实现移动语义和完美转发。
    • 示例
      int&& rref = 20; // rref 是一个右值引用,绑定到右值 20

4. move移动语义

将内存的所有权从一个对象转移到另外一个对象,高效的移动用来替换效率低下的复制,对象的移动语义需要实现移动构造函数(move constructor)和移动赋值运算符(move assignment operator)

假如我们有两个指针 一个指针A,一个指针B,指针A指向了一个很复杂的内容,此时我们需要指针B指向这个很复杂的内容,之后我们就不需要指针A了,它可以滚蛋了,可以析构掉了,这个就是移动语义,结果就是将原来指针A指向的内存交给了指针B,指针A不指向任何内存。相当于B偷走了A的东西。相对的有移动语义就有复制语义,复制语义就是B指针要想获得同样的内容就会发生拷贝,大部分都是深拷贝(浅拷贝,深拷贝有机会我会补上一篇博客的),结果就是指针A指向一片内存,指针B指向了另一片内存,但两片内存中存储的内容是相同的,大大的浪费性能。 

5. forward完美转发

完美转发是指在模板函数中将传递给函数的参数以原样的值类别(左值或右值)转发给另一个函数。完美转发的目标是避免不必要的复制或移动操作,同时保持参数的值类别。

高效传参技术

  • 实现方式

    • 使用模板函数:定义一个模板函数来接收参数。

    • 使用 std::forward:将参数转发给另一个函数,保持其值类别。

      std::forward 是一个标准库函数模板,主要用于完美转发。
      它的作用是根据参数的值类别(左值或右值)转发参数,从而确保转发过程中不会发生不必要的复制或移动。
      

6. std::move 和 std::forward

  • std::move:用于将左值强制转换为右值引用,从而允许移动语义。它不保留参数的值类别,仅用于移动。
  • std::forward:用于在模板中完美转发,保持参数的原始值类别(左值或右值),确保转发过程中不会改变值类别。

7. C++11中nullptr和NULL的区别

  • 类型安全:nullptr 提供更好的类型安全性,相比 NULL 可以避免类型混淆。

  • 定义:nullptr 是 C++11 的新关键字,NULL 是 C 语言中的宏。

  • 兼容性:nullptr 只能用于指针类型,而 NULL 可以是整型常量,可能导致不明确的类型推断。

8. C++中两种自动类型推导

auto关键字告诉编译器根据变量的初始化表达式自动推导变量的类型。这在声明变量时非常有用,特别是当你不确定变量的确切类型,或者类型比较复杂难以书写时。

decltype关键字允许你根据一个表达式的类型来定义一个新的类型名。

decltype(auto)允许你在声明变量的同时推导出变量的类型,并且保留表达式的CV限定符(const和volatile限定符)以及引用类型。这对于确保类型正确性和避免不必要的类型转换特别有用。

9. atomic底层实现机理

Atomic(原子操作) 是指一种操作在执行的过程中不会被中断或干扰。它确保在并发的环境中,一个操作要么全部完成,要么根本不执行,从而避免竞态条件(race condition)的发生。

在多线程编程中,多个线程可能会同时操作同一个数据。为了避免不同线程对共享数据的操作出现冲突,必须确保某些操作是原子的,意思是这些操作不能被分割或中途中断。

C++11 的 std::atomic 概述

std::atomic 是 C++11 提供的一个模板类,用于在多线程环境中安全地操作共享数据而无需显式使用互斥锁(如 std::mutex)。它确保对变量的读写操作是原子的,避免竞态条件(race condition)的发生。

  • 类型

    • 基本类型:int, bool, char等
    • 指针类型:int*
    • 具备无锁特性的自定义类型(需满足特定的条件,如可拷贝、可移动等)
  • 内存序模型
    C++11 的原子操作允许开发者指定内存序,以控制操作之间的可见性和顺序性。
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 常见原子操作
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 底层实现原理

    C++11 的 std::atomic 底层实现依赖于现代处理器提供的原子操作指令内存屏障,结合编译器对这些硬件特性的支持。它通过直接与硬件交互,保证了多线程环境下对共享数据的并发访问的原子性。

    1. 硬件原子操作指令

      现代 CPU 架构都提供硬件支持的原子指令,用于实现 std::atomic。这些指令可以确保在多处理器环境中对共享内存的操作不会出现竞争条件(race condition),即不会在其他处理器中间插入对该内存地址的访问
      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    2. 内存屏障

      内存屏障(又称为内存栅栏)用于确保指令的执行顺序。

      不同的硬件架构和编译器可能会对程序指令进行乱序执行(out-of-order execution)以优化性能。内存屏障可以防止这种乱序执行,确保某些关键操作按预期顺序执行。

    3. 缓存一致性

      现代多核处理器使用缓存来加速数据访问,但这也带来了缓存一致性问题。为了确保多线程对共享变量的一致性,处理器使用缓存一致性协议(如 MESI 协议)来同步不同核的缓存。

      原子操作会触发缓存一致性协议,确保某个内存地址的更新会被所有处理器核立即看到。
      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    4. 编译器优化

      C++11 的 std::atomic 实现依赖于编译器提供的内建函数(intrinsic functions)来生成适当的硬件原子指令和内存屏障。

10. shared_ptr计数线程安全怎么实现

在 C++ 中,std::shared_ptr 是一种智能指针,它通过引用计数(reference counting)来管理对象的生命周期。每次 shared_ptr 被复制、赋值或销毁时,引用计数会相应增加或减少,当引用计数变为零时,shared_ptr 所指向的对象会被自动销毁。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

11. 为什么引入右值、纯右值、将亡值

  • 右值 是一种短暂存在的值,它分为纯右值(临时值、字面量)和将亡值(即将销毁的对象)。

  • 引入这些值类别的目的是为了优化性能,通过移动语义避免不必要的拷贝。

  • 右值引用(T&&) 和 将亡值(xvalue) 支持开发者在处理临时对象时转移资源,降低内存开销。

  • 这些改进使得 完美转发 和其他高级技术成为可能,提升了 C++ 的表达能力和执行效率。

右值及其分类的引入使得 C++ 程序可以更精细地管理对象生命周期和资源,从而在性能和安全性上都得到了显著的提升。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

12. 对一个const容器使用move会发生什么

对 const 容器使用 std::move 时,虽然 std::move 将容器转换为右值引用,但由于 const 限制,移动操作无法改变容器的状态,因此不会真正发生移动。结果是,会回退到拷贝操作,即对 const 容器进行拷贝构造或拷贝赋值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13. 传参能否传const&&,会发生什么

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

14. unordered_map如何将一个大数映射到bucket数量上

  • unordered_map 使用哈希函数将大数(或任何类型的键)转换为一个哈希值。

  • 然后通过 hash_value % bucket_count 的方式将这个大数映射到哈希表中的桶。

  • 如果发生冲突,unordered_map 使用链地址法(通常是链表)来存储冲突的键值对。

  • 在负载过高时,unordered_map 会自动进行重哈希以保持性能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

15. 对vector的earse方法具体怎么实现的

std::vector 是 C++ 标准库中的动态数组类,提供了许多方法来操作其元素。erase 是 std::vector 中用于删除元素的方法。这个方法的核心是在保持动态数组连续性的情况下删除元素,并重新调整容器的大小。理解 erase 的实现过程需要了解动态数组的特性以及如何在数组中删除元素并维护顺序。

  • erase 方法用于删除 std::vector 中的一个或多个元素。

  • 删除操作通过将删除位置之后的元素向左移动来保持数组的连续性。

  • 单元素删除和多元素删除的核心逻辑相似,区别在于是否批量移动。

  • erase 方法具有线性时间复杂度,且返回删除位置后第一个元素的迭代器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


http://www.ppmy.cn/news/1527610.html

相关文章

idea连接docker 自动化部署

进入Linux服务器 vim /lib/systemd/system/docker.service将 ExecStart/usr/bin/dockerd -H fd:// --containerd/run/containerd/containerd.sock 替换为 ExecStart/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock新建文件 Dockerfile配置Dockerfile文…

CTF比赛中的Git相关题目解题思路

在CTF比赛中,涉及Git相关的题目通常会考察参赛者对Git仓库的了解,尤其是如何利用公开或不完整的Git仓库来恢复源代码或获取敏感信息。本文将结合一些常见的工具和步骤,详细介绍如何解决这类题目。 背景 Git是一种分布式版本控制系统&#…

中国农业银行——开源软件一体化管理平台

【金融机构开源技术应用创新成果案例 第十二期】 中国农业银行——开源软件一体化管理平台 申报单位:中国农业银行股份有限公司 技术领域:开源软件管理 技术产品:Git、Gitea、Spring-boot、Mybatis 业务场景:开源软件准入、使用、安全治理、目录发布、内外部开源等 应…

Go第三方框架--gin框架(三)

5. net/http框架源码-- 多路复用的实现 这块核心功能对应 1.3 的圆圈2,所属代码如下图: run代码涉及的操作不是gin框架的核心,还记的我说过gin是在net/http的基础上操作的吗,我们来看下gin和net/http包的关联关系。 gin: 主要建…

Java重修笔记 第五十六天 坦克大战(六)多线程基础 - 线程同步、死锁

多线程同步机制 多线程编程中,一些敏感数据可能会被多个线程同时访问造成数据混乱(例如票数),使用线程同步机制,通过锁对象(对象实例或类实例)的方式来保证该段代码在任意时刻,最多…

ram和rom的种类迭代和介绍

RAM(随机存取存储器)在计算机和电子设备中扮演着至关重要的角色。随着技术的发展,RAM有多个迭代和种类,每个种类在速度、功耗和使用场景上有所不同。以下是RAM的详细迭代种类及介绍。 1. SRAM(Static RAM,…

linux-软件包管理-包管理工具(Debian 系)

Linux 软件包管理概述 在Linux系统中,软件包管理是系统维护的核心部分之一。通过软件包管理器,用户可以方便地安装、更新、删除和查询系统中的软件包。每个Linux发行版通常都有自己专属的包管理工具,这些工具基于不同的包格式。例如&#xf…

pycharm连接远程linux服务器上的docker进行深度学习训练

实习过程中由于GPU都在服务器上,编辑代码很麻烦。并且服务器上配置了docker的环境,所以用pycharm连接远程服务器的docker进行深度学习,这样在本地调用远程服务器的GPU和环境,更方便一点,将这个过程记录下来&#xff0c…

CentOS中使用DockerCompose方式部署带postgis的postgresql(附kartoza/docker-postgis镜像下载)

场景 CentOS中使用Docker部署带postgis的postgresql: CentOS中使用Docker部署带postgis的postgresql_centos postgis插件在容器中如何安装-CSDN博客 上面使用Docker搜索和拉取kartoza/postgis时并没有任何限制。 当下如果不能科学上网时,大部分镜像源…

力扣150题——多维动态规划

交错字符串 题目 97. 交错字符串 - 力扣(LeetCode) 思路 用dp[i][j]代表s1的前i个字母和s2的前s2个字母能否交错组成s3的前ij-1的子串 状态转移方程即为 如果 s1[i-1] s3[i j - 1],并且 dp[i-1][j] 为 true,则 dp[i][j] 也…

vmware中的ubuntu系统扩容分区

1.虚拟机关机 右击虚拟机/设置,进入虚拟机设置 3.启动虚拟机,进入命令行 4.fdisk -l查看要扩展的分区名 5.resize要扩容的分区 su root parted /dev/sda resizepart 3 100% fdisk -l resize2fs /dev/sda3 df -T完成 6.其他 进入磁盘管理 fdisk /d…

oracle 如何查询表被锁

在Oracle数据库中,查询表是否被锁可以通过多种方式实现。以下是一些常用的方法来查询Oracle数据库中的表锁情况: 1. 使用V$LOCKED_OBJECT视图 V$LOCKED_OBJECT是Oracle提供的动态性能视图,用于显示当前被锁定的对象信息。通过查询该视图&am…

XML_Tomcat_HTTP

第四章 XML_Tomcat10_HTTP 一 XML XML是EXtensible Markup Language的缩写,翻译过来就是可扩展标记语言。所以很明显,XML和HTML一样都是标记语言,也就是说它们的基本语法都是标签。 可扩展 三个字表面上的意思是XML允许自定义格式。但这不代…

使用 Istio 缓解电信 5G IoT 微服务 Pod 架构的安全挑战

在 Kubernetes 集群中部署微服务在 5G 电信中至关重要。但是,它也带来了重大的安全风险。虽然防火墙规则和代理提供了初始安全性,但 Kubernetes 中的默认通信机制(例如未加密的网络流量和缺乏访问控制)本质上是不安全的。这种不安…

《拿下奇怪的前端报错》:nvm不可用报错`GLIBC_2.27‘‘GLIBCXX_3.4.20‘not Found?+ 使用docker构建多个前端项目实践

有些前端的小伙伴可能会好奇,nvm是什么?这里接简单介绍下,它是一个Nodejs版本管理工具。为什么需要它呢?当然是需要多个Nodejs版本的时候,那什么时候需要多个Nodejs版本?那肯定是在有点年头的公司了&#x…

使用git命令

git add . git commit -m "commit message" 拉取 git pull origin <branch-name> 推送 git push origin <branch-name> 创建新分支 git branch <new-branch-name> # 切换到新分支 git checkout <new-branch-name> 合并分支 git mer…

区块链先驱孙宇晨:引领价值传播,激发行业创新活力

​孙宇晨&#xff0c;这位被誉为“区块链布道师”的年轻企业家&#xff0c;以其独特的愿景和行动力在区块链行业中脱颖而出。作为波场TRON的创始人&#xff0c;他不仅是区块链技术的倡导者&#xff0c;更是一位不懈推动行业发展的领导者。他通过自身的努力和影响力&#xff0c;…

C++ | Leetcode C++题解之第415题字符串相加

题目&#xff1a; 题解&#xff1a; class Solution { public:string addStrings(string num1, string num2) {int i num1.length() - 1, j num2.length() - 1, add 0;string ans "";while (i > 0 || j > 0 || add ! 0) {int x i > 0 ? num1[i] - 0 …

进程监控与管理详解

一、进程的定义: 进程process是正在运行的程序,包括: 分配的内存地址空间 安全属性、包括所有权和特权 一个或多个线程 进程状态 进程的环境包括: 本地和全局变量 当前调度上下文…

算法入门-贪心1

第八部分&#xff1a;贪心 409.最长回文串&#xff08;简单&#xff09; 给定一个包含大写字母和小写字母的字符串 s &#xff0c;返回通过这些字母构造成的最长的回文串 的长度。 在构造过程中&#xff0c;请注意 区分大小写 。比如 "Aa" 不能当做一个回文字符串…