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

第六章 提高性能及操作硬件的能力

6.1 常量表达式

6.1.1 运行时常量性与编译时常量性

大多数情况下,const描述的是运行时常量性,也即是运行时数据的不可更改性。但有时候我们需要的却是编译时的常量性,这是const关键字无法保证的。例如:

c++11使用constexpr关键字声明常量表达式,不仅限于函数,也可以作用于数据声明,以及类的构造函数。

6.1.2 常量表达式函数

在函数返回类型前加入关键字constexpr来使其称为常量表达式函数,另外还有几点要求:

1.函数体只有单一的return返回语句。

2.函数必须返回值。

3.在使用前必须已有定义。

4.return返回语句表达式中不能使用非常量表达式的函数、全局数据,且必须是一个常量表达式。

多条语句的写法一般无法通过编译,但是一些不会产生实际代码的语句在常量表达式函数中使用,不会引起编译错误,例如static_assert、using、typedef等。

6.1.3 常量表达式的值

由constexpr关键字修饰的变量就是所谓的常量表达式值。常量表达式值必须被一个常量表达式赋值,必须在使用前被初始化。

编译器可以不为常量表达式的值生成数据,仅将其当做编译器的值。

c++11允许编译时的浮点数常量表达式的值,标准要求编译时浮点常量表达式值的精度至少等于或高于运行时的浮点数常量的精度。

c++11标准中,constexpr关键字不能用于修饰自定义类型的定义。正确的做法是定义自定义常量构造函数。

常量表达式的构造函数也有两点约束:

1.函数体必须为空。

2.初始化列表只能由常量表达式来赋值。

虽然声明的是常量表达式构造函数,但编译时的常量性体现在类型上。

PRCfound的成员变量也具有编译时的常量性。

c++11不允许常量表达式作用于virtual的成员函数。

6.1.4 常量表达式的其他应用

常量表达式可以用于模板函数。c++11规定,当声明为常量表达式的模板函数后,当某个该模板函数的实例化结果不满足常量表达式的需求的话,constexpr会被自动忽略。实例化后的函数将成为一个普通函数。

常量表达式可以用于递归函数。例如:

基于模板的编译时期运算的编程方式,通常被称为模板元编程。例如:

并不是使用了constexpr,编译器就一定会在编译时期对常量表达式函数进行值计算。

6.2 变长模板

6.2.1 变长函数和变长的模板参数

c++11支持c99的变长宏。printf则使用了c语言的函数变长参数特征。例子:

变长函数的第一个参数表示的是变长参数的个数。而被调用者中,需要通过一个类型为va_list的数据结构ap来辅助地获得参数。首先使用va_start函数对ap进行初始化,使得ap称为被传递的变长参数的一个句柄。而后代码再使用va_arg函数从ap中将参数一一取出用于运算。

一方面,变长函数本身完全无法知道参数数量或者参数类型。另一方面,c++需要更为现代化的变长参数的实现方式,类型和变量同时能传递给变长参数的函数。一个好的方式就是使用c++的函数模板。c++98中标准要求函数模板始终具有数目确定的模板参数及函数参数。

类也需要不定长度的模板参数。c++98中没有变长模板,tuple能够支持的模板参数数量实际上是由标准库定义了多少个不同参数版本的tuple模板而决定的。c++11中tuple可以接受任意多个不同类型的元素的集合。

6.2.2 变长模板:模板参数包和函数参数包

c++11中的一个tuple变长类模板:template<typename ...Elements> class tuple;其中Elements被称为模板参数包(template parameter pack)。对于实例化的tuple模板类:tuple<int, char, double>,编译器可以将多个模板参数打包为单个的模板参数包Elements,即Elements在进行模板推导的时候,就是一个包含int、char和double三种类型的类型集合。

与普通的模板参数类似,模板参数包也可以是非类型的,比如:

一个模板参数包在模板推导时会被认为是模板的单个参数。为了使用模板参数包,总是需要将其解包,通常通过包扩展(pack expansion)的表达式来完成。

template<typename ...A> class Template:private B<A...>{};

这里的表达式A...就是一个包扩展,参数包会在包扩展的位置上展开为多个参数。比如:

这里类模板B总是接受两个参数的前提下,如果我们声明了一个Template<X,Y,Z>就会发生模板推导的错误。c++11中,实现tuple模板使用了递归的手段,使得模板参数包在实例化时能够层层展开,直到参数包中的参数逐渐耗尽或者到达某个数量的边界为止。

除了变长的模板类,在c++11中还可以声明变长模板的函数。除了声明变长个模板参数的模板参数包,也可以声明成函数参数包,比如:template<typename ...T> void f(T ...args);由于T是个变长模板参数,因此args是对应于这些变长类型数据,即函数参数包。c++11中标准要求函数参数包必须唯一,且是函数的最后一个参数,模板参数包没有这样的要求。

6.2.3 变长模板:进阶

标准定义了以下7种参数包可以展开的位置:

1.表达式

2.初始化列表

3.基类描述列表

4.类成员初始化列表

5.模板参数列表

6.通用属性列表

7.lambda函数的捕捉列表

语言的其他地方则无法展开参数包。在不同位置展开参数包会有不同的效果,例如:

类似情况也发生在函数声明上:

除了扩展外,c++11标准还引入了新的操作sizeof...,作用是计算参数包中的参数个数。

变长模板的参数也可以是模板。变长模板参数也可以用于完美转发。

6.3 原子类型与原子操作

6.3.1 并行变成、多线程与c++11

c++11之前,c/c++程序使用线程主要使用POSIX线程(pthread)和OpenMP编译器指令两种标称模型来完成程序的线程化。

c++11标准引入了多线程的支持。一个最为重要的部分是在原子操作中引入了原子类型的概念。

6.3.2 原子操作与c++11原子类型

原子操作就是多线程程序中最小的且不可并行化的操作。通常情况下原子操作都是通过互斥的访问来保证的。c++11标准之前,需要在c/c++代码中嵌入内联的汇编代码。如果想实现粗粒度的互斥,借助POSIX标准的pthread库中的互斥锁也可以做到:

c++11对并行编程更为良好的抽象,实现相同功能就简单多了:

c++11不需要为原子数据类型显式地声明互斥锁或调用加锁、解锁的API,线程就能够对变量互斥地进行访问。c++11标准定义的是原子类型,而传统面向过程编程语言里使用的是原子操作。

c++11与c11标准都支持原子类型。可以通过#include<cstdatomic>头文件来使用对应于内置类型的原子类型定义。

更为普遍地,可以使用atomic类模板定义任意的原子类型,例如:std::atomic<T> t;而c11则需要使用新关键字_Atomic来完成。

多个线程通常只能访问单个原子类型的拷贝,因此原子类型只能从其模板参数类型中进行构造,不允许原子类型进行拷贝构造、移动构造,以及使用operator=等,以防发生意外。

不过从atomic<T>类型的变量来构造其模板参数类型T的变量则是可以的。比如:

因为atomic类模板总是定义了从atomic<T>到T的类型转换函数。

原子类型能够在线程间保持原子性,主要还是因为编译器能够保证针对原子类型的操作都是原子操作。c++11标准将对原子操作定义为atomic模板类的成员函数,对于内置类型而言,主要是重载一些全局操作符来完成的。

对于大多数原子类型而言,都可以执行读(load),写(store)、交换(exchange)、比较并交换(compare_exchange_weak/compare_exchange_strong)等操作。

atomic_flag是无锁的,

c++11原子操作还可以包含一个参数:memory_order。

6.3.3 内存模型,顺序一致性与memory_order

内存模型通常是一个硬件上的概念,表示的是机器指令是以什么样的顺序被处理器执行的。如果处理器的执行顺序总是按指令顺序,通常称这样的内存模型为强顺序的。反之,则为弱顺序的。如果允许编译器在单个线程中打乱指令的运行顺序,则可能提升并行程序的性能。弱顺序内存模型的平台,如果要保证指令执行顺序,通常要在汇编指令中加入一条所谓的内存栅栏指令。例如PowerPC中的sync指令迫使已经进入流水线中的指令都完成后处理器才执行sync以后的指令。

c++11中的内存模型,要保证代码的顺序一致性,必须同时做到:

1.编译器保证原子操作的指令间顺序不变,即保证产生的读写原子类型的变量的机器指令与代码编写者看到的是一致的。

2.处理器对原子操作的汇编指令的执行顺序不变。对于x86这样的强顺序的体系结构而言,并没有问题;而对于PowerPC这样的弱顺序的体系结构而言,则要求编译器在每次原子操作后加入内存栅栏。

c++11中,原子类型的成员函数总是保证了顺序一致性。对于x86平台来说,禁止了编译器对原子类型变量间的重排序优化;对于PowerPC这样的平台,不仅禁止了编译器优化,还插入了大量的内存栅栏。对于意图提高性能的多线程程序而言,无疑是一种性能伤害。

c++11中,设计者给出的解决方式是让程序员为原子操作指定所谓的内存顺序:memory_order。

(相关使用,未完待续。。。)

6.4 线程局部存储

线程局部存储变量,就是拥有线程生命期及线程可见性的变量。c++11使用thread_local修饰符声明线性局部存储变量。TLS变量的内存的静态/动态分配问题经常被讨论。而c++11标准只对语法做了统一,对其实现并没有做任何性能上的规定。如果想得到最佳的平台上的TLS运行性能,最好还是阅读代码运行平台的相关文档。

6.5 快速退出:quick_exit与at_quick_exit

有关终止的函数:

terminate:terminate函数式c++异常处理的一部分,包含在<exception>头文件里。没有被捕捉的异常就会导致terminate函数的调用。terminate函数在默认情况下,会调用abort函数,不过用户可以通过set_terminate函数来改变默认行为。

abort:abort函数不会调用任何析构函数,默认情况下,它会向合乎POSIX标准的系统抛出一个信号:SIGABRT。如果为信号设定一个信号处理程序的话,操作系统将默认地释放进程所有的资源,从而终止程序。

exit:exit函数会正常调动自动变量的析构函数,还会调用atexit注册的函数,属于正常退出的范畴。

main或者使用exit函数调用结束程序,会导致类的析构函数依次将零散的内存还给操作系统,这是意见费时的工作,实际上,这些内存将在进程结束时由操作系统统一回收。这种情况下,我们往往需要能够更快地退出程序。

在多线程情况下,我们要使用 exit 函数来退出程序的话,通常需要向线程发出一个信号,并等待线程结束后再执行析构函数、atexit 注册的函数等。这样的退出方式有的时候并不能够像预期那样工作,比如说线程中的程序在等待 I/O 行结束等。在一些更为复杂的情况下,可能还会遭遇到一些因为信号顺序而导致的死锁状况。一旦出现了这样的问题,程序往往就会被“卡死”而无法退出。

为此c++11标准引入了quick_exit函数,该函数不执行析构函数而只是使程序终止。quick_exit函数也属于正常退出。使用at_quick_exit注册函数也可以在quick_exit的时候被调用。

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

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

相关文章

精品Nodejs实现的在线菜谱食谱美食学习系统的设计与实现

《[含文档PPT源码等]精品Nodejs实现的在线菜谱学习系统的设计与实现[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 操作系统&#xff1a;Windows 10、Windows 7、Windows…

day5--java基础编程:异常,内部类

6 异常 6.1 异常概述 出现背景&#xff1a; 在使用计算机语言进行项目开发的过程中&#xff0c;即使程序员把代码写得尽善尽美&#xff0c;在系统的运行过程中仍然会遇到一些问题&#xff0c;因为很多问题不是靠代码能够避免的&#xff0c;比如:客户输入数据的格式&#xff0c…

技术博客官网也是一个不错的学习平台(第411篇)

技术博客官网也是一个不错的学习平台(第411篇) 今天的主题是OSPF 大纲 技术成就梦想51CTO-中国知名的数字化人才学习平台和技术社区 OSPF 概念型问题_wx655f0abb3511b的技术博客_51CTO博客 OSPF协议介绍及配置 - airoot - 博客园 (cnblogs.com) 一、OSPF概述 回顾一下距离矢…

图片处理软件,批量缩放图片尺寸

无论是社交媒体上的分享&#xff0c;还是工作中的图片素材&#xff0c;往往大小不一、形状不同&#xff0c;这时如何批量高效地对这些图片进行缩放就显得尤为重要。传统的图片处理软件&#xff0c;不仅操作复杂&#xff0c;而且处理速度慢&#xff0c;更无法实现批量化处理。但…

《Spring Cloud学习笔记:微服务保护Sentinel + JMeter快速入门》

Review 解决了服务拆分之后的服务治理问题&#xff1a;Nacos解决了服务治理问题OpenFeign解决了服务之间的远程调用问题网关与前端进行交互&#xff0c;基于网关的过滤器解决了登录校验的问题 流量控制&#xff1a;避免因为突发流量而导致的服务宕机。 隔离和降级&#xff1a…

【LeetCode:17. 电话号码的字母组合 | 递归 + 回溯 + 组合】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

计算机网络【DNS】

DNS 基本概述 与 HTTP、FTP 和 SMTP 一样&#xff0c;DNS 协议也是应用层的协议&#xff0c;DNS 使用客户-服务器模式运行在通信的端系统之间&#xff0c;在通信的端系统之间通过下面的端到端运输协议来传送 DNS 报文。但是 DNS 不是一个直接和用户打交道的应用。DNS 是为因特…

【损失函数】SmoothL1Loss 平滑L1损失函数

1、介绍 torch.nn.SmoothL1Loss 是 PyTorch 中的一个损失函数&#xff0c;通常用于回归问题。它是 L1 损失和 L2 损失的结合&#xff0c;旨在减少对异常值的敏感性。 loss_function nn.SmoothL1Loss(reductionmean, beta1.0) 2、参数 size_average (已弃用): 以前用于确定是…

从PDF中提取图片

由于工作需要&#xff0c;要从pdf文件中提取出图片保存到本地&#xff0c;项目中就引用到了Apache PDFBox库。 1 什么是Apache PDFBox? Apache PDFBox库&#xff0c;一个用于处理PDF文档的开源Java工具。它允许用户创建全新的PDF文件&#xff0c;操作现有的PDF文档&#xff0…

利用ufun对部件进行操作(新建、打开、保存、另存、关闭等)

一、概述 在NX二次开发中我们常常会用到新建、打开、保存、另存为和关闭命令&#xff0c;这些函数一般放在UF_part.h头文件下&#xff0c;下面针对以上有关功能结合案例进行说明。 二、功能函数结合案例说明 2.1新建文件创建块保存功能 1&#xff09;NXOpenC代码 #include …

4.32 构建onnx结构模型-Erf

前言 构建onnx方式通常有两种&#xff1a; 1、通过代码转换成onnx结构&#xff0c;比如pytorch —> onnx 2、通过onnx 自定义结点&#xff0c;图&#xff0c;生成onnx结构 本文主要是简单学习和使用两种不同onnx结构&#xff0c; 下面以 Erf 结点进行分析 方式 方法一&…

抖音详情API:从零开始构建抖音应用

随着短视频的兴起&#xff0c;抖音已经成为了一个全球范围内的热门平台。对于开发人员而言&#xff0c;利用抖音详情API从零开始构建抖音应用具有巨大的潜力和机会。本文将为你提供从零开始构建抖音应用的指南&#xff0c;包括开发环境搭建、API请求格式、用户认证等关键环节&a…

移动硬盘打不开怎么办?没有比这更好的办法了

移动硬盘打不开是常见故障&#xff0c;可能的原因有很多&#xff0c;例如硬盘驱动器故障、文件系统损坏、分区表错误等。本文将详细分析这些原因&#xff0c;并提供相应的解决方法&#xff0c;帮助您解决移动硬盘打不开的问题。 当移动硬盘打不开时&#xff0c;为了保留其中的文…

[LitCTF 2023]Vim yyds

[LitCTF 2023]Vim yyds wp 题目页面如下&#xff1a; 搜索一番&#xff0c;没有发现任何信息。题目描述中说到了源码泄露&#xff0c;那么先进行目录扫描。 dirsearch 目录扫描 命令&#xff1a; dirsearch -u "http://node4.anna.nssctf.cn:28588/"返回结果&…

使用docker轻量化部署snmp agent(SNMPv2访问)

文章目录 服务器环境说明单机部署&#xff08;非挂载conf文件版&#xff09;debian:buster-slim容器简介实现步骤创建Dockerfile创建SNMP配置文件 (snmpd.conf)构建Docker镜像运行Docker容器 注意补充复制容器文件到本地容器、镜像操作 单机部署&#xff08;挂载conf文件版&…

12.30序列检测(重叠、不重叠、连续、不连续、含无关项)——移位寄存器,状态机;状态机(二段式,三段式)

状态机-重叠序列检测 timescale 1ns/1nsmodule sequence_test2(input wire clk ,input wire rst ,input wire data ,output reg flag ); //*************code***********//parameter S00, S11, S22, S33, S44;reg [2:0] state, nstate;always(posedge clk or negedge rst) b…

CLion Nova:全新的C/C++ IDE

CLion Nova是一款备受期待的集成开发环境&#xff08;IDE&#xff09;&#xff0c;由JetBrains专门为C/C开发者设计。这款IDE提供了许多新的功能和改进&#xff0c;使用 ReSharper C/Rider C 语言引擎而不是 CLion “传统” 引擎&#xff0c;以满足C/C开发者的需求。目前预览版…

网络层解读

基本介绍 概述 当两台主机之间的距离较远(如相隔几十或几百公里&#xff0c;甚至几千公里)时&#xff0c;就需要另一种结构的网络&#xff0c;即广域网。广域网尚无严格的定义。通常是指覆盖范围很广(远超过一个城市的范围)的长距离的单个网络。它由一些结点交换机以及连接这些…

多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测

多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测 目录 多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测预测效果基本介绍模型背景程序设计参考资料 预测效果 基本介绍 MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入…

Mastercam各版本安装指南

Mastercam下载链接 https://pan.baidu.com/s/1OldNR0ERqJFrEN24uu3j0Q?pwd0531 1.鼠标右击【Mastercam2024(64bit)】压缩包&#xff08;win11及以上系统需先点击“显示更多选项”&#xff09;【解压到 Mastercam2024(64bit)】。 2.打开解压后的文件夹&#xff0c;鼠标右击【…