当前位置: 首页 > news >正文

C++11新特性① | C++11 常用关键字实战详解

目录

1、引言

2、C++11 新增关键字详解

2.1、auto

2.2、override

2.3、final

2.4、nullptr

2.5、使用=delete阻止拷贝类对象

2.6、decltype

2.7、noexcept

2.8、constexpr

2.9、static_assert


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html       C++11新特性很重要,作为C++开发人员很有必要去学习,不仅笔试面试时会涉及到,开源代码中会大规模的使用。以很多视频会议及直播软件都在使用的开源WebRTC项目为例,WebRTC代码中大篇幅地使用了C++11及以上的新特性,要读懂其源码,必须要了解这些C++的新特性。所以,接下来一段时间我将结合工作实践,给大家详细讲解一下C++11的新特性,以供借鉴或参考。

1、引言

       为了提升C++语言的灵活性和效率,C++11引入了多个关键字,比如auto、overide、final、nullptr、decltype、constexpr、noexcept、static_assert等。本文结合编码实战,主要介绍一下C++11中引入的常用新关键字。

C++11及以上新标准引入了很多新特性,使C++变得更加灵活,但也使得C++的特性变得更加臃肿,使C++变得更加难以驾驭。

2、C++11 新增关键字详解

2.1、auto

       编程时常常需要将表达式的值赋值给变量,这要求在声明变量时清楚地指出表达式的类型,但有时很难确定。C++11标准引入了auto类型说明符,用它能让编译器替我们去分析表达式所属的类型。auto变量必须要初始化,因为编译器要通过初始值来推算该auto变量的类型。

       自动类型推导,用于从初始化表达式中推断出变量的数据类型(实际上是在编译时对变量进行了类型推导,所以不会对程序的运行效率造成不良影响)。示例如下:

auto i = 2;      // int类型
auto d = 1.0;  //  double类型
auto str = "hello word"; // const char*
auto ch =  'A';   // char类型
auto func = less<int>();  // 函数指针
vector<int> vtList; 
auto iter = vtList.begin();  // 选代器类型
auto p = new foo();         // 自定义类型 

2.2、override

       派生类在重写基类的虚函数时,可以在函数前添加virtaul标记,这样我们看到这个标识后就知道该函数是重写基类的虚函数了。在C++11引入override关键字之后,我们就可以使用override来更明显标识重写的函数。

       给派生类的函数添加override标识的好处是,一方面使程序员重写基类的意图更加清晰,另一方面让编译器发现一些错误,如果我们用override标识了派生类的某个函数,但该函数没有覆盖基类的虚函数,则编译器会报错。

class Base
{
public:virtual void func() const{cout << __func__ << std::endl;}
}class Derived :public Base
{
public:virtual void func() overide{cout << __func__ << std::endl;}
}

2.3、final

       有时我们需要定义这样一种类,我们不希望其他类继承它。或者不想考虑它是否适合做一个基类。为了实现这一目的,C++11引入了一个用来阻止继承的关键字final,将该关键字放到类名之后,即表示该类不能被继承。示例如下:

class Base{ /*   */};
class Last final : public Base { /*   */};

        还可以用该关键字去修饰一个类的成员函数时,来阻止该函数被派生类重写:

class Base
{
public:virtual void func() const{cout << __func__ << std::endl;}
}class Derived :public Base
{
public:virtual void func() overide final{cout << __func__ << std::endl;}
}

2.4、nullptr

       nullptr是为了解决原来C++中NULL的二义性问题而引进的一种新的类型,因为NULL实际上代表的是0。最好使用字面值nullptr去初始化一个指针,表示当前是空指针。nullptr是一种特殊类型的字面值,它可以被转换成任意其他的指针类型。

       为什么说nullptr可以解决NULL的二义性呢?可以来看个实例:

void func( int );
void func( int* );

比如上面的两个重载函数,我们要调用func函数,如果传入NULL(NULL实际上代表的是0,可以隐式转换成void*,进而转成int*),两个函数感觉都能调进去,编译器不知道调用的是哪个,这样就产生了二义性,编译时会报错。而传nullptr参数时,编译就不报错了,就比较明确了,调用的就是void func( int* )。    

       nullptr_t是变量类型,其值就是nullptr,可以看看nullptr_t的定义:

#ifdef __cplusplusnamespace std{typedef decltype(__nullptr) nullptr_t;  // nullptr_t被声明为__nullptr的类型}using ::std::nullptr_t;
#endif

如果函数参数中有nullptr_t时,不用指定变量名的,直接在函数体中对应的参数设置成nullptr就可以了。以shared_ptr智能指针的某个构造函数为例:(代码来源Visual C++中的智能指针的源码实现)

template<class _Dx,class _Alloc,enable_if_t<conjunction_v<is_move_constructible<_Dx>,_Can_call_function_object<_Dx&, nullptr_t&>>, int> = 0>
shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)  // 参数类型为nullptr_t,对应的值就是nullptr
{    // construct with nullptr, deleter, allocatorSetpda(nullptr, _STD move(_Dt), _Ax);
}    

2.5、使用=delete阻止拷贝类对象

       其实这个地方的=delete不是关键字!

       在C++11新标准中,我们通过将拷贝构造函数和拷贝复制函数定义为删除的函数来阻止拷贝。在函数后面加上=delete,函数就变成了删除的函数。对于删除的函数,我们虽然声明了它,但不能用任何方式使用它。

       以智能指针类std::unique_ptr为例,该智能指针类不支持拷贝构造和赋值操作,主要支持所有权移动操作。所以在类的定义中,将该类的拷贝构造函数和赋值函数设置为=delete函数,用来阻止拷贝构造和赋值:(这是一个经典的面试题:std::unique_ptr智能指针是如何禁止拷贝和复制的?)

unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;

我们不能通过不实现拷贝构造函数和赋值函数去实现这个目标,因为当我们不实现这两个函数时,编译器会自动帮我们生成默认的拷贝构造函数和赋值函数。

       在没有C++的=delete的标识之前,可以将拷贝构造函数和赋值函数设置为private的,这样在类外部不能使用这两个函数。

2.6、decltype

       有时希望通过表达式的类型推断出要定义的变量的类型,但不想用该表达式的值来初始化变量去推断变量的类型,为了满足这一要求,C++11标准引入了decltype类型指示符,它的作用是推断操作数的数据类型并返回,编译器只分析推断表达式的类型,但不去计算表达式的值(不对表达式求值)。

const int nVal = 0;
decltype(nVal) y = 1;
decltype(t + u); // 其中t和u是数据类型,不对表达式t+u进行求值,只去推断t+u表达式的数据类型。

       类型说明符生成指定表达式的类型,编译时根据表达式的类型去推导出类型,示例如下:

int i;
struct A
{double x; 
};
const A* a = new A();decltype(i)            x2; // int
dec1type (a->x)       x3; // double
dec1type((a->x))       x4;   // double&

2.7、noexcept

       在C++11标准中,提供了noexcept关键字,用来指定某个函数不抛出异常。将该关键字放到函数的参数列表之后,如下:

void func() noexcept;            // 这里noexcept作为修饰符

对于用户及编译器来说,预先知道某个函数不抛出异常很有好处。首先,知道函数不会抛出异常有助于简化调用该函数的代码;其次,如果编译器确认 函数不抛出异常,它就能执行某些特殊的优化操作,而这些优化操作并不适用于可能出错的代码。

       可能会出现一种情况,虽然函数使用noexcept关键字声明不抛出异常,但实际上函数内部还是抛出了异常。一旦一个noexcept函数抛出了异常,程序就会调用std::terminate()终止程序,以确保不在运行时抛出异常的承诺。

       指明某个函数不抛出异常,这样调用者不必考虑如何处理异常了,无论是函数确实不抛出异常,还是抛出异常后被强行终止,调用者都无需为此负责。

       在C++98中,用throw()来声明不抛出异常,throw(异常类型)声明可能抛出的异常类型。noexcept效率比throw更高一些,因为编译器可以用std::terminate()来终止程序运行,而throw异常机制会有一些额外开销,如函数栈依次展开并析构自动变量。

       在程序进程的内存不足时,new操作会抛出bad_alloc异常,内存分配失败,这个问题我们以前讲过,处理办法是:在new时传如一个std::nothrow参数,让new在申请不到内存时不要抛出异常,直接返回为NULL,这样我们就可以通过返回的地址是否为NULL(空),判断是否是内存申请失败了,代码如下:

#include <iostream>int main(){char *p = NULL;int i = 0;do{p = new(std::nothrow) char[10*1024*1024]; // 每次申请10MBi++;Sleep(5);}while(p);if(NULL == p){std::cout << "分配了 " << (i-1)*10 << " M内存"         //分配了 1890 Mn内存第 1891 次内存分配失败           << "第 " << i << " 次内存分配失败";}return 0;
}

当然,程序进程内存不足时,业务没法正常展开和执行了,让程序还活着,其实也没多大意义了。 

2.8、constexpr

       指值不会改变并且在编译过程就能得到计算结果的表达式。 C++11 新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量是否是一个常量表达式。声明为constexpr 的变量一定是一个常量,而且必须用常量表达式初始化。

constexpr int mf= 20;           // 20 是常量表达式
constexor int limit = mf + 1;   // mf + 1 是常量表达式
constexor int sz = size();         // 只有当size是一个constexpr函数时才是一条正确的语句

       constexpr也可以修饰函数,一旦函数声明为constexpr,则函数的返回值类型及所有形参的类型都必须是字面值类型,而且函数体中有且只能有一条retrun语句。

constexpr int new_sz(){ retrun 20; };

2.9、static_assert

       static_assert用来做编译期间的断言,因此叫做静态断言。语法如下:

static_assert(常量表达式,提示字符串)

比如:

static_assert(sizeof(int) < sizeof(unsigned int), "int is not smaller than unsigned int");

如果第一个参数常量表达式的值为真(true或者非零值),那么static_assert不做任何事情,就像它不存在一样,否则会产生一条编译错误,错误位置就是该static_assert语句所在行,错误提示就是第二个参数提示字符串。

       使用static_assert,我们可以在编译期间发现更多的错误,用编译器来强制保证一些契约,并帮助我们改善编译信息的可读性。

相关文章:

C++11新特性① | C++11 常用关键字实战详解

目录 1、引言 2、C11 新增关键字详解 2.1、auto 2.2、override 2.3、final 2.4、nullptr 2.5、使用delete阻止拷贝类对象 2.6、decltype 2.7、noexcept 2.8、constexpr 2.9、static_assert VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xf…...

VUE3学习小记(2)- ref 与 reactive

ref() 在组合式 API 中&#xff0c;推荐使用ref()函数来声明响应式状态&#xff1a; import { ref } from vueconst count ref(0) ref() 接收参数&#xff0c;并将其包裹在一个带有 .value 属性的 ref 对象中返回&#xff1a; const count ref(0)console.log(count) // {…...

基于单片机的万年历温度无线传输控制系统系统

一、系统方案 本设计采用DS1302采集年月日时分秒&#xff0c;DS18B20采集温度值&#xff0c;按键设置温度报警上下限&#xff0c;实际测量温度低于下限或高于上限&#xff0c;蜂鸣器报警&#xff0c;同时将测量温度上传到蓝牙助手。 二、硬件设计 原理图如下&#xff1a; 三…...

ElementUI浅尝辄止19:Badge 标记

出现在按钮、图标旁的数字或状态标记。 1.如何使用&#xff1f; 可展示新消息数量。 //定义value属性&#xff0c;它接受Number或者String。<el-badge :value"12" class"item"><el-button size"small">评论</el-button> <…...

nginx两台负载均衡服务器之间使用keepalived实现高可用

目录 高可用HAkeepalived实现高可用VRRP协议单VIP架构VIP飘移脑裂双VIP架构&#xff08;互为主从&#xff09;keepalived监控 、执行脚本notify 高可用HA 单点故障&#xff1a;某个重要的功能只有一份&#xff0c;如果他出现问题&#xff0c;会导致全局不能使用 “高可用性”…...

如何将Express项目部署到Vercel

什么是Vercel&#xff1f; 想必好多前端同学都知道Vercel吧&#xff01;如果还不了解的同学也没关系&#xff0c;好好看这篇文章&#xff0c;认识认识Vercel&#xff0c;我想对你部署项目有一定帮助。 Vercel 是一个云平台&#xff0c;用于托管和部署静态网站、前端应用程序以…...

Java作业3

1.下面代码的运行结果是&#xff08;C&#xff09; public static void main(String[] args){String s;System.out.println("s"s);}A.代码编程成功&#xff0c;并输出”s” B.代码编译成功&#xff0c;并输出”snull” C.由于String s没有初始化&#xff0c;代码不…...

ARM编程模型-寄存器组

Cortex A系列ARM处理器共有40个32位寄存器,其中33个为通用寄存器,7个为状态寄存器。usr模式和sys模式共用同一组寄存器。 通用寄存器包括R0~R15,可以分为3类: 未分组寄存器R0~R7分组寄存器R8~R14、R13(SP) 、R14(LR)程序计数器PC(R15)、R8_fiq-R12_fir为快中断独有 在不同模…...

C++ string

目录 string类介绍访问&#xff1a;[ ] 遍历迭代器遍历范围for遍历 容量相关&#xff1a;修改相关&#xff1a;编码表的了解写时拷贝的了解string的模拟 STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&a…...

百亿级访问量,如何做缓存架构设计

说在前面 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如阿里、网易、有赞、希音、百度、网易、滴滴的面试资格&#xff0c;遇到一几个很重要的面试题&#xff1a;&#xff1a; 分布式缓存系统&#xff0c;如何架构&#xff1f;百亿级访…...

(数字图像处理MATLAB+Python)第十一章图像描述与分析-第三、四节:几何表述和形状描述

文章目录 一&#xff1a;几何描述&#xff08;1&#xff09;像素间几何关系A&#xff1a;邻接与连通B&#xff1a;距离 &#xff08;2&#xff09;像素间几何特征A&#xff1a;位置B&#xff1a;方向C&#xff1a;尺寸 &#xff08;3&#xff09;程序 二&#xff1a;形状描述&a…...

20230901工作心得:IDEA列操作lambda表达式加强版用法

今天是中小学开学时间&#xff0c;亦是9月的开始&#xff0c;继续努力。 今日收获较大的有四个地方&#xff0c;先说这四点。 1、IDEA列操作 使用场景&#xff1a;需要批量将Excel表格里的数据插入到数据库中&#xff0c;此时需要写大量的insert SQL语句。 比如像这样的&am…...

macOS Sonoma 14beta 7(23A5337a)更新发布,附黑/白苹果系统镜像

系统介绍&#xff08;镜像请前往黑果魏叔官网下载&#xff09; 黑果魏叔8 月 31 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 14 开发者预览版 Beta 7 更新&#xff08;内部版本号&#xff1a;23A5337a&#xff09;&#xff0c;本次更新距离上次发布隔了 8 天。 …...

QT基础教程之九Qt文件系统

QT基础教程之九Qt文件系统 文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库&#xff0c;提供了跨平台的文件操作能力。Qt 通过QIODevice提供了对 I/O 设备的抽象&#xff0c;这些设备具有读写字节块的能力。下面是 I/O 设备的类图&#xff08;Qt5&#xff09;&#…...

OpenCV(十八):图像直方图

目录 1.直方图统计 2.直方图均衡化 3.直方图匹配 1.直方图统计 直方图统计是一种用于分析图像或数据的统计方法&#xff0c;它通过统计每个数值或像素值的频率分布来了解数据的分布情况。 在OpenCV中&#xff0c;可以使用函数cv::calcHist()来计算图像的直方图。 calcHist(…...

mac pro 查看隐藏文件夹

在Mac上查看隐藏文件夹可以使用以下方法&#xff1a; 使用终端&#xff1a; 打开终端应用程序&#xff0c;位于“应用程序”文件夹的“实用工具”子文件夹中。 在终端中&#xff0c;输入以下命令&#xff0c;然后按回车键&#xff1a; defaults write com.apple.finder AppleS…...

软件测试/测试开发丨Selenium 高级定位 Xpath

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27036 一、xpath 基本概念 XPATH是一门在XML文档中查找信息的语言 XPATH使用路径表达式在XML文档中进行导航 XPATH的应用非常广泛&#xff0c;可以用于UI自…...

各类注意力机制Attention——可变形注意力

目录 《Attention is all you need 》稀疏Attention残差Attention通道注意力空间注意力时间注意力可变形注意力 《Attention is all you need 》 稀疏Attention 残差Attention 通道注意力 空间注意力 时间注意力 实际上序列类任务也属于时间注意力&#xff0c;比如transformer…...

桥接模式:连接抽象与实现

欢迎来到设计模式系列的第八篇文章&#xff01;在之前的几篇文章中&#xff0c;我们已经学习了许多常见的设计模式&#xff0c;今天我们将继续探讨另一个重要的设计模式——桥接模式。 桥接模式简介 桥接模式是一种结构型设计模式&#xff0c;它主要用于将抽象部分与实现部分…...

同步推送?苹果计划本月推出 iOS17和iPadOS17,你的手机支持吗?

据报道&#xff0c;苹果公司计划在本月推出 iOS 17 和 iPadOS 17 正式版更新。与去年不同的是&#xff0c;这次更新将同时发布&#xff0c;而不是分别发布。根据彭博社的一位消息人士马克・古尔曼的说法&#xff0c;苹果公司认为 iOS 17 和 iPadOS 17 的第八个测试版已经非常接…...

方案展示 | RK3588开发板Linux双摄同显方案

iTOP-RK3588开发板使用手册更新&#xff0c;后续资料会不断更新&#xff0c;不断完善&#xff0c;帮助用户快速入门&#xff0c;大大提升研发速度。 RK3588开发板载4路MIPI CAMERA摄像头接口、MIPI CSI DPHY的4.5Gbps、2.5Gops的MIPI CSI CPHY&#xff0c;四路同时输入&#xf…...

数据库-多表设计

概述&#xff1a; 项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个表结构之间也存在着各种联系&#xff0c;基本分为三种&#xff1a; 一对…...

一个简单的文件系统(MinixFS)实现解析

1. Minix文件系统概要 Minix file system 是 Andrew S. Tanenbaum 在 1980 年代发明的文件系统, 并随着 Minix 操作系统一起于 1987 年发布。 Linus 编写 Linux 内核第一个版本的时候, 使用的也是 Minix FS, Linux 至今依然提供了对 Minix FS 的支持。Minix FS 结构简单, 易于…...

地图投影-2亚当斯方形

说明 亚当斯方形 II 投影显示了一个方形的世界。它是 Oscar S. Adams 于 1925 年提出的两种投影之一。该投影为等角投影&#xff0c;但方形的四个角除外。在 Adams 最初的设计中&#xff0c;该投影将赤道和中央经线显示为方形的对角线。 此投影的一个有利属性是可以进行细分或…...

atcoder库中类欧(类欧几里得算法)floor_sum用法

https://atcoder.jp/contests/practice2/tasks/practice2_c 求 ∑ i 0 N − 1 f l o o r ( ( A i B ) / m ) \sum_{i 0}^{N - 1} floor((A \times i B) / m) ∑i0N−1​floor((AiB)/m) 直接使用即可&#xff1a; ansfloor_sum(n, m, A, B); //注意顺序...

后端面试话术集锦第 十一 篇:mybatis面试话术

这是后端面试集锦第十一篇博文——mybatis面试话术❗❗❗ 1. 介绍下mybatis,说说它的优缺点是什么? Mybatis是一个半ORM(对象关系映射)的持久层框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程…...

SpringBoot运维实用篇、打包、运行、高级配置、多环境开发、日志

文章目录 SpringBoot运维实用篇YW-1.SpringBoot程序的打包与运行程序打包程序运行SpringBoot程序打包失败处理命令行启动常见问题及解决方案SpringBoot项目快速启动&#xff08;Linux版&#xff09; YW-2.配置高级YW-2-1.临时属性设置YW-2-2.配置文件分类YW-2-3.自定义配置文件…...

springdoc-openapi-ui 整合 knife,多模块分组,脚手架

pom文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…...

04-MySQL02

1、什么是索引下推&#xff1f; 索引下推&#xff08;index condition pushdown &#xff09;简称ICP&#xff0c;在Mysql5.6的版本上推出&#xff0c;用于优化查询。 需求: 查询users表中 "名字第一个字是张&#xff0c;年龄为10岁的所有记录"。 SELECT * FROM u…...

实现跨境电商测评和采退、LU卡、LU货最安全的系统方案

首先你要有一个稳定的测评环境系统&#xff0c;这个是做自养号退款、撸货、撸卡的基础。测评环境系统有很多&#xff0c;从早期的虚拟机&#xff0c;模拟机&#xff0c;云手机&#xff0c;VPS等等。这些系统方案先不说成本高&#xff0c;最重要的是成功率很低&#xff0c;所以一…...