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

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

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

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

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...