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,我们可以在编译期间发现更多的错误,用编译器来强制保证一些契约,并帮助我们改善编译信息的可读性。

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

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

相关文章

微服务介绍

在认识微服务之前&#xff0c;需要先了解一下与微服务对应的单体式&#xff08;Monolithic&#xff09;式架构。在Monolithic架构中&#xff0c;系统通常采用分层架构模式&#xff0c; 按技术维度对系统进行划分&#xff0c;比如持久化层、业务逻辑层、表示层。 Monolithic架构…

PYTHON知识点学习-字典

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由 Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

Si24R2F+畜牧 耳标测体温开发资料

Si24R2F是针对IOT应用领域推出的新款超低功耗2.4G内置NVM单发射芯片。广泛应用于2.4G有源活体动物耳标&#xff0c;带实时测温计步功能。相较于Si24R2E&#xff0c;Si24R2F增加了温度监控、自动唤醒间隔功能&#xff1b;发射功率由7dBm增加到12dBm&#xff0c;距离更远&#xf…

el-table 垂直表头

效果如下&#xff1a; 代码如下&#xff1a; <template><div class"vertical_head"><el-table style"width: 100%" :data"getTblData" :show-header"false"><el-table-columnv-for"(item, index) in getHe…

Android图形-架构1

目录 引言 Android图形的关键组件&#xff1a; Android图形的pipeline数据流 BufferQueue是啥&#xff1f; 引言 Android提供用于2D和3D图形渲染的API&#xff0c;可与制造商的驱动程序实现代码交互&#xff0c;下面梳理一下Android图形的运作原理。 应用开发者通过三种方…

阿里后端开发:抽象建模经典案例

0.引言 在互联网行业&#xff0c;软件工程师面对的产品需求大都是以具象的现实世界事物概念来描述的&#xff0c;遵循的是人类世界的自然语言&#xff0c;而软件世界里通行的则是机器语言&#xff0c;两者间跨度太大&#xff0c;需要一座桥梁来联通&#xff0c;抽象建模便是打…

Ceph基础知识和基础架构认识

1 Ceph基础介绍 Ceph是一个可靠地、自动重均衡、自动恢复的分布式存储系统&#xff0c;根据场景划分可以将Ceph分为三大块&#xff0c;分别是对象存储、块设备存储和文件系统服务。在虚拟化领域里&#xff0c;比较常用到的是Ceph的块设备存储&#xff0c;比如在OpenStack项目…

Android开机动画

Android开机动画 1、BootLoader开机图片2、Kernel开机图片3、系统启动时&#xff08;BootAnimation&#xff09;动画3.1 bootanimation.zip位置3.2 bootanimation启动3.3 SurfaceFlinger启动bootanimation3.4 播放开机动画playAnimation3.6 开机动画退出检测3.7 简易时序图 4、…

【Vue】 Vue3 安装说明,适合小白新手

1、独立版本 我们可以在 Vue.js 的官网上直接下载最新版本, 并用 下载 Vue.js https://unpkg.com/vuenext 2、使用 CDN 方法 以下推荐国外比较稳定的两个 CDN&#xff0c;国内还没发现哪一家比较好&#xff0c;目前还是建议下载到本地。 Staticfile CDN&#xff08;国内&am…

【Python】爬虫练习-爬取豆瓣网电影评论用户的观影习惯数据

目录 前言 一、配置环境 1.1、 安装Python 1.2、 安装Requests库和BeautifulSoup库 1.3.、安装Matplotlib 二、登录豆瓣网&#xff08;重点&#xff09; 2.1、获取代理 2.2、测试代理ip是否可用 2.3、设置大量请求头随机使用 2.4、登录豆瓣网 三、爬取某一部热门电影…

【Linux】高级IO --- 多路转接,select,poll,epoll

所有通过捷径所获取的快乐&#xff0c;无论是金钱、性还是名望&#xff0c;最终都会给自己带来痛苦 文章目录 一、五种IO模型1.什么是高效的IO&#xff1f;&#xff08;降低等待的时间比重&#xff09;2.有哪些IO模型&#xff1f;哪些模型是高效的&#xff1f;3.五种IO模型的特…

简单理解微服务限流、降级、熔断

微服务限流、降级、熔断分别都是什么意思&#xff0c;我们平时工作中为什么要关注这些东西呢&#xff1f; 公司不断的发展壮大&#xff0c;一开始处于蛮荒时代&#xff0c;咱们从单体应用过渡到微服务的时候&#xff0c;可能还是那一套单体的思想&#xff0c;再加上用户量可能…

大模型参数高效微调技术原理综述(二)-BitFit、Prefix Tuning、Prompt Tuning

随着&#xff0c;ChatGPT 迅速爆火&#xff0c;引发了大模型的时代变革。然而对于普通大众来说&#xff0c;进行大模型的预训练或者全量微调遥不可及。由此&#xff0c;催生了各种参数高效微调技术&#xff0c;让科研人员或者普通开发者有机会尝试微调大模型。 因此&#xff0c…

2023-9-1-虚拟网卡学习

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f4a5;&#x1f4a5;&#x1f4a5;欢迎来到&#x1f91e;汤姆&#x1f91e;的csdn博文&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f49f;&#x1f49f;喜欢的朋友可以关注一下&#xf…

日常开发小点汇总(1)

1.浮动元素 生成一个浮动流&#xff0c;块级元素看不到&#xff0c;文本、行内属性元素及行内元素可见 <div class"demo1"></div><span>123</span><div class"demo2"></div>.demo1 {width: 100px;height: 100px;backg…

在 linux 虚拟机上安装配置 hive

目录 一 下载hive 安装包 二 解压 hive 并配置环境变量 三 配置hive 的配置文件 四 更新 guava 五 hive初始化 六 开启远程连接 七 使用datagrip 连接 hive 一 下载hive 安装包 百度网盘资源如下&#xff1a; 链接: https://pan.baidu.com/s/18jF-Qri0hc52_rtL61O0YQ?…

Unity中神秘的Transform和transform(小写)的关系

1.为什么Transform类是保护的不能通过new 来实例化对象,也没有静态函数,而Rotate()这种方法却属于它,该如何访问? Transform 类还是被保护的不允许用户修改! protected Transform(); 是一个受保护的构造函数,不能直接实例化 Transform 类。 2.为甚么transform可以访问Tr…

2023年行研行业研究报告

第一章 行业概述 1.1 行研行业 行业定义为同一类别的经济活动&#xff0c;这涉及生产相似产品、应用相同生产工艺或提供同类服务的集合&#xff0c;如食品饮料行业、服饰行业、机械制造行业、金融服务行业和移动互联网行业等。 为满足全球金融业的需求&#xff0c;1999年8月…

蓝桥杯备赛(Day5)——二叉树

二叉树存储 普通做法,二叉树一个节点包括结点的数值以及指向左右子节点的指针 在class Node中 def __init__(self,s,l=None,r=None):self.val=Noneself.l=lself.r=r 在竞赛中,我们往往使用静态数组实现二叉树,定义一个大小为N的静态结构体数组,使用其来存储一棵二叉树。…

使用生成式 AI 增强亚马逊云科技智能文档处理

数据分类、提取和分析对于处理大量文档的组织来说可能具有挑战性。传统的文档处理解决方案是手动的、昂贵的、容易出错的,并且难以扩展。利用 Amazon Textract 等 AI 服务,亚马逊云科技智能文档处理(IDP)允许您利用业界领先的机器学习(ML)技术来快速准确地处理任何扫描文档或图…