《深入理解C++11:C++11新特性解析与应用》笔记五

第五章 提高类型安全

5.1 强类型枚举

5.1.1 枚举:分门别类与数值的名字

具名枚举类型一般声明类似:enum Gender { Male, Female }。

匿名枚举类型可以使用三种方式实现:

第一种方式时宏,比如

#define Male 0

#define Female 1

宏的弱点在于其定义的知识预处理阶段的名字,会干扰正常代码。

第二种方式时匿名的enum,比如enum { Male, Female};

c++中更受推荐的是第三种方式,静态变量,例如const static int Male = 0;

静态变量能够得到编译时检查,作用域局限于文件内,但是会在目标代码中产生实际的数据,相比而言匿名的枚举似乎更好用。

5.1.2 有缺陷的枚举类型

c/c++的enum有个奇怪的设定,就是具名enum类型的名字和enum的成员的名字都是全局可见的。

上面例子中的两个General都是全局的名字,因此编译器会报错。解决的办法是将它们声明在不同的namespace之下,然后用限定namespace的方式去访问它。

另外,由于c中枚举被设计为常量数值的别名的本性,所以枚举的成员总是可以被隐式地转换为整型。很多时候这是不安全的。为解决这一问题,一般会对枚举类型进行封装。

但是封装过于复杂,封装采用静态成员,enum变成了非POD。传递参数的时候如果参数是结构体,就不能使用寄存器来传参,而整型可以通过寄存器传递。class封装版本的枚举作为函数参数传递,就会带来一定性能损失。

此外,枚举类型所占用的空间大小也是一个不确定的量。因为标准规定,c++枚举所基于的基础类型由编译器具体指定实现。

5.1.3 强类型枚举以及c++11对原有枚举类型的扩展

c++11引入一种新的枚举类型,即枚举类,又称强类型枚举。

声明强类型枚举只需在enum后面加上关键字class,比如:

enum class Type { General, Light, Medium, Heavy };

强类型枚举的几个优势:

1.强作用域,强类型枚举成员的名称不会被输出到其父作用域空间

2.转换限制,强类型枚举成员的值不可以与整型隐式地互相转换。

3.可以指定底层类型。默认底层类型为int,可以在枚举名称后面加上“: type”来显式指定底层类型,type可以试除wchar_t之外的任何整型。

c++11还对原来的枚举进行了扩展。首先底层的基本类型也可以跟强类型枚举一样,显式地由程序员指定。第二则是枚举成员的名字除了会自动输出到父作用域,也可以在枚举类型定义的作用域内有效。这两点都是向后兼容的。

此外在声明强类型枚举的时候,也可以使用enum struct关键字,两者没有任何区别。

匿名的enum class可能什么也做不了。

5.2 堆内存管理:只能指针与垃圾回收

5.2.1 显式内存管理

显式内存管理常见问题:

一野指针:内存单元已被释放,但是之前指向它的指针却还在被使用。

二重复释放。

三内存泄漏。

c++11新保准对智能指针进行了改进,还提供了所谓的最小垃圾回收的支持。

5.2.2 c++11的智能指针

c++98中智能指针通过一个模板类型“auto_ptr”来实现。auto_ptr以对象的方式管理堆分配的内存,并在适当的时间(比如析构),释放所获得的堆内存。这种堆内存管理的方式只需要程序员将new操作返回的指针作为auto_ptr的初始值即可,程序员不用再显式地调用delete。

auto_ptr存在一些缺点,譬如拷贝时候返回一个左值,不能调用delete[]等,所在在c++11标准中废弃了。c++11中改用unique_ptr, shared_ptr及weak_ptr等智能指针来自动回收堆分配的对象。

每个智能指针都重载了*运算符,可以用来访问所分配的堆内存。智能指针析构或者调用reset成员的时候,智能指针能释放其拥有的堆内存。

unique_ptr唯一拥有所指向的对象内存,仅能通过标准库的move函数来转移。unique_ptr是一个删除了拷贝构造函数、保留了移动构造函数的指针封装类型。

shared_ptr允许多个智能指针共享地拥有同一堆分配对象的内存,实现上采用了引用计数。shared_ptr调用reset成员函数只会引起引用计数的降低,而不会导致堆内存的释放。只有在引用计数归零的时候,shared_ptr才会真正释放所占有的堆内存的空间。

weak_ptr可以指向shared_ptr指针所指向的对象内存,却不拥有该内存。使用weak_ptr成员lock,可以返回其指向内存的一个shared_ptr对象,且在所指对象内存已经无效时,返回指针空值,可用于验证shared_ptr的有效性。

5.2.3 垃圾回收的分类

垃圾回收的方式主要分为两大类:

1.基于引用计数的垃圾回收器

优点是简单,不会造成程序暂停,也不会对系统缓存或者交换空间造成冲击。但是难以处理环形引用问题,产生的额外开销也不小。

2.基于跟踪处理的垃圾回收器

跟踪处理的垃圾回收处理机制更为广泛地应用。其基本方法是产生跟踪对象的关系图,然后进行垃圾回收。使用跟踪方式的垃圾回收算法主要有以下几种:

(1)标记清除(mark-sweep)

该算法将程序中正在使用的对象视为根对象,从根对象开始查找它们所引用的堆空间,并在这些堆空间上做标记。当标记结束后,所有被标记的对象就是可达对象(reachable object)或活对象(live Object),而没有被标记的对象就被认为是垃圾,在第二步的清扫阶段就会被回收掉。

这种方法的特点是活的对象不会被移动,但是其存在会出现大量的内存碎片的问题。

(2)标记整理(mark-compact)

该方法标记的方法和标记清除一样,但是标记完之后,不再遍历所有对象清扫垃圾了,而是将活的对象向左靠齐,这就解决了内存碎片的问题。

标记整理的方法有个特点就是移动活的对象,因此相应地,程序中所有对堆内存的引用都必须更新。

(3)标记拷贝(mark-copy)

该算法将堆空间分为两部分:from和to。刚开始系统只从from的堆空间里面分配内存,当from分配满的时候系统就开始垃圾回收:从from对空间里找出所有活的对象,拷贝到to的堆空间里。这样一来,from的堆空间里面就全剩下垃圾了。而对象被拷贝到to里之后,在to里是紧凑排列的。接下来是需要将from和to交换一下角色,接着从新的from里面开始分配。

标记拷贝算法的一个问题是堆的利用率只有一半,而且也需要移动活的对象。这种算法其实是标记整理的另一种实现而已。

5.2.4 c++与垃圾回收

指针的灵活对垃圾回收带来了很大的困扰。被隐藏的指针会导致编译器在分析指针可达性时出错。c++11解决这种问题的方法就是让程序员利用新的接口来提示编译器代码中存在着指针不安全的区域。

5.2.5 c++11与最小垃圾回收支持

c++11为了做到最小的垃圾回收支持,首先对安全的指针进行了定义,也就是c++11中所谓的安全派生(safely derived)的指针。安全派生的指针是指向由new分配的对象或其子对象的指针。安全派生指针的操作包括:

1.在解引用基础上的引用,比如:&*p。

2.定义明确的指针操作,比如:p+1。

3.定义明确的指针转换,比如static_cast<void *>(p)。

4.指针和整型之间的reinterpret_cast,比如reinterpret_cast<intptr_t>(p)。intptr_t是c++11中一个可选择实现的类型,其长度等于平台上指针的长度。

可通过get_pointer_safety函数查询编译器是否支持最小垃圾回收。

如果代码中出现了指针不安全使用的情况,可以通过一些API来通知垃圾回收器不得回收该内存。即需要声明该内存为可达到的:

declare_reachable()显式地通知垃圾回收器某一个对象应被认为可达到的,即使它的所有指针都对回收器不可见。undeclare_reachable()则可以取消这种可达声明。

declare_reachable只需要传入一个简单的void *指针,但undeclare_reachable通常被设计为一个函数模板。

有时候程序员会选择在一大片连续的堆内存上进行指针式操作,为了让垃圾回收器不关心该区域,也可以使用declare_no_pointers及undeclare_no_pointers函数来告诉垃圾回收器该内存区域不存在有效的指针。

5.2.6 垃圾回收的兼容性

必须限制指针的使用或者使用declare_reachable/undeclare_reachable、declare_no_pointers/undeclare_no_pointers来让一些不安全的指针使用免于垃圾回收器的检查。

此外c++标准对指针的垃圾回收支持仅限于系统提供的new操作符分配的内存,而malloc分配的内存则会被认为总是可达的。

更为现实的状况是本书写作时,垃圾回收特性还没有得到任何表一起的支持,即使是所谓的最小垃圾回收。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安全生产知识竞赛活动方案

为进一步普及安全生产法律法规知识&#xff0c;增强安全意识&#xff0c;提高安全技能&#xff0c;经研究&#xff0c;决定举办以“加强安全法治、保障安全生产”为主题的新修订《安全生产法》知识竞赛活动&#xff0c;现将有关事项通知如下&#xff1a; 一、活动时间&#xf…

机器学习(二) -- 数据预处理(3)

系列文章目录 机器学习&#xff08;一&#xff09; -- 概述 机器学习&#xff08;二&#xff09; -- 数据预处理&#xff08;1-3&#xff09; 未完待续…… 目录 前言 tips&#xff1a;这里只是总结&#xff0c;不是教程哈。本章开始会用到numpy&#xff0c;pandas以及matpl…

【Kubernetes】什么是 kubectl ?

什么是 kubectl &#xff1f; 1.什么是 kubectl &#xff1f;2.Kubernetes 内部结构3.Kubernetes API 的作用 1.什么是 kubectl &#xff1f; 在学习如何更有效地使用 kubectl 之前&#xff0c;您应该对它是什么以及它如何工作有一个基本的了解。从用户的角度来看&#xff0c;…

助力打造智慧数字课堂,基于YOLOv8全系列【n/s/m/l/x】不同参数量级模型开发构建教学课堂场景下学生课堂行为检测识别分析系统

近年来&#xff0c;随着行为检测技术的发展&#xff0c;分析学生在课堂视频中的行为&#xff0c;以获取他们的课堂状态和学习表现信息已经成为可能。这项技术对学校的教师、管理人员、学生和家长都非常重要。使用深度学习方法自动检测学生的课堂行为是分析学生课堂表现和提高教…

计算机视觉技术-目标检测数据集

目标检测领域没有像MNIST和Fashion-MNIST那样的小数据集。 为了快速测试目标检测模型&#xff0c;我们收集并标记了一个小型数据集。 首先&#xff0c;我们拍摄了一组香蕉的照片&#xff0c;并生成了1000张不同角度和大小的香蕉图像。 然后&#xff0c;我们在一些背景图片的随机…

分享好用稳定快递查询api接口(对接简单)

提供实时查询和自动识别单号信息。稳定高效&#xff0c;调用简单方便&#xff0c;性价比高&#xff0c;一条链接即可对接成功。 使用数据平台该API接口需要先注册后申请此API接口。申请成功后赠送免费次数&#xff0c;可直接在线请求接口数据。 接口地址&#xff1a;https://…

ArkUI中自定义组件的生命周期

文章概叙 本文主要是介绍下在作为page以及component的时候的生命周期&#xff0c;以及调用API等应该在哪个生命周期使用。 书接上回 之前的博客已经结束了对底部栏的操作&#xff0c;现在开始需要关注到具体内容的对接了。 而开发的第一步&#xff0c;我们对页面的生命周期…

你了解螺杆螺纹吗?

螺杆的螺纹部分是其核心部分之一&#xff0c;主要作用是传递旋转运动和力矩&#xff0c;丝杆的螺纹形状和参数对其性能和使用寿命有着重要影响&#xff1b;常用的螺杆螺纹可以分为&#xff1a;三角牙螺纹、梯形牙螺纹、矩形牙螺纹、锯齿牙螺纹、滚珠螺纹。 1、三角牙&#xff1…

Tomcat与Servlet是什么关系

Tomcat与Servlet是什么关系 Apache Tomcat和Servlet之间存在密切的关系&#xff0c;可以说它们是一对密切合作的组件。下面是它们的关系&#xff1a; Tomcat是Servlet容器&#xff1a; Tomcat是一个开源的、轻量级的Servlet容器。Servlet容器是一个Web服务器扩展&#xff0c;用…

【YOLOV8实例分割——详细记录环境配置、自定义数据处理到模型训练与部署】

前言 Ultralytics YOLOv8是一种前沿的、最先进的&#xff08;SOTA&#xff09;模型&#xff0c;它在前代YOLO版本的成功基础上进行了进一步的创新&#xff0c;引入了全新的特性和改进&#xff0c;以进一步提升性能和灵活性。作为一个高速、精准且易于操作的设计&#xff0c;YOL…

LOAM: Lidar Odometry and Mapping in Real-time 论文阅读

论文链接 LOAM: Lidar Odometry and Mapping in Real-time 0. Abstract 提出了一种使用二维激光雷达在6自由度运动中的距离测量进行即时测距和建图的方法 距离测量是在不同的时间接收到的&#xff0c;并且运动估计中的误差可能导致生成的点云的错误配准 本文的方法在不需要高…

软件工程期末复习习题

知识点总结 第一章&#xff1a;软件工程概述 1、软件的定义&#xff1a;在运行中能提供所希望的功能与性能的程序使程序能够正确运行的数据及其结构描述软件研制过程和方法所用的文档。 2、软件危机&#xff1a;软件开发的生产率远远不能满足客观需要。开发的软件产品往往不能…

MyBatis-config.xml配置文件

1、基本介绍&#xff1a; mybatis的核心配置文件(mybatis-config.xml)&#xff0c;比如配置jdbc连接信息&#xff0c;注册mapper等等&#xff0c;我们需要对这个配置文件有详细的了解。 官网地址有详细介绍 mybatis – MyBatis 3 | 配置 2、properties属性 在通常的情况下&am…

【Apache Doris】自定义函数之 JAVA UDF 详解

【Apache Doris】自定义函数之 JAVA UDF 详解 一、背景说明二、原理简介三、环境信息3.1 硬件信息3.2 软件信息 四、IDE准备五、JAVA UDF开发流程5.1 源码准备5.1.1 pom.xml5.1.2 JAVA代码 5.2 mvn打包5.2.1 clean5.2.2 package 5.3 函数使用5.3.1 upload5.3.2 使用 六、注意事…

TV端Web页面性能优化实践

01 背景 随着互联网技术的持续创新和电视行业的高速发展&#xff0c;通过电视观看在线视频已经逐渐成为大众的重要娱乐方式。奇异果App作为在TV设备上用户活跃度最高的应用之一&#xff0c;为广大用户提供了丰富的内容播放服务&#xff0c;除此之外&#xff0c;同样有会员运营、…

苹果CMS超级播放器专业版无授权全开源,附带安装教程

源码介绍 超级播放器专业版v1.0.8&#xff0c;内置六大主流播放器&#xff0c;支持各种格式的视频播放&#xff0c;支持主要功能在每一个播放器内核中都相同效果。 搭建教程 1.不兼容IE浏览器 2.php版本推荐7.4 支持7.1~7.4 3.框架引入不支持同时引入多个播放器 json对接教…

【Linux】Linux

Linux 文章目录 Linux1. 简介2. 目录结构3. vi/vim 的使用4. 网络配置4.1 配置网络ip地址4.2 配置主机名或ip映射4.3 远程登陆及上传下载 5. 系统管理5.1 service 服务管理&#xff08;CentOS 6 版本&#xff09;5.2 systemctl 服务管理&#xff08;CentOS 7 版本&#xff09;5…

SpringMVC源码解析——DispatcherServlet的逻辑处理

DispatcherServlet类相关的结构图如下&#xff1a; 其中jakarta.servlet.http.HttpServlet的父类是jakarta.servlet.GenericServlet&#xff0c;实现接口jakarta.servlet.Servlet。我们先看一下jakarta.servlet.Servlet接口的源码如下&#xff1a; /*** 定义所有servlet必须实…

tcpdump出现permission denied

在使用tcpdump -i eth0 src host 192.168.0.184 and ip and port 22 -nn -w ping.pacp命令抓包并把抓到的数据保存到ping.pacp时&#xff0c;出现了权限错误的报错。但实际上我这里用的是root用户执行的命令。 查阅man手册发现: 在tcpdump中&#xff0c;-Z选项用于在启动数据…

思维训练-怎样设计一个MQ

架构师需要做各种设计&#xff0c;要不断地提高自己的设计能力。这有没有方法可以训练呢&#xff1f;有的&#xff0c;就是看到什么、想到什么&#xff0c;就假设对面坐着产品经理&#xff0c;一起讨论怎么把它设计出来。比如怎样设计一个MQ 我&#xff1a;首先我确认一下需求。…