当前位置: 首页 > 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 的第八个测试版已经非常接…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...