【C++】C++11新增特性

目录

C++11简介:

1、统一的列表初始化:

std::initializer_list

2、自动类型推导:

auto:

decltype:

3、final 和 override

final:

override:

4、默认成员函数控制:

显示缺省函数:

删除默认函数:

5、左值和右值:

概念补充:

代码示例:

左值引用与右值引用:

两者的联系和区别:

右值引用的意义:

6、完美转发:

7、lambda表达式:

8、可变参数列表:

9、包装器:

function包装器:

bind(绑定):


C++11简介:

C++11,也被称为C++0x,是C++编程语言的一个重要更新版本,它于2011年正式被ISO标准委员会批准。相比于C++98,C++11带来了大量的新特性和改进,其中包含了约140个新特性,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率。本篇主要介绍一些使用的多且实用的一些语法:

1、统一的列表初始化:

在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。例如:

C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自 定义的类型,使用初始化列表时,可添加等号(=),也可不添加。

struct Student
{int _x;int _y;
};
int main()
{// 两种写法一样的int x1 = 1;int x2{ 2 };// 可以省去 = int array1[]{ 1, 2, 3, 4, 5 };int array2[5]{ 0 };Student s{ 1, 2 };return 0;
}

创建对象时也可以使用列表初始化方式调用构造函数初始化

class A
{
public:// 如果不想让隐式类型转换发生可以加关键字: explicit// explicit A(int x, int y)A(int x, int y):_x(x), _y(y){}// 单参数A(int x):_x(x), _y(x){}private:int _x;int _y;
};int main()
{// 多参数的隐式类型转换// 本质是构造一个A对象,然后用这个对象去拷贝构造(编译器会进行优化, 就变成了直接构造)A a1 = { 1,2 };// 例如: A& a3 = {2, 2}; 这样子的就不行,但转换成下面的就可以const A& a3 = { 2,2 }; // 因为右边会产生临时变量,但临时变量具有常性// 当然也可以不加 = ,如 A a1{ 1,2 }; 但是不太推荐这么写 return 0;
}

std::initializer_list

initializer_list 是 C++11 引入的一个特性,用于表示某种类型对象的数组。它允许使用花括号 {} 包围的初始值列表来初始化对象或函数参数。initializer_list 通常与构造函数结合使用,以提供一种灵活的方式来初始化集合(如数组、向量等)或执行基于多个值的初始化。

(本质就是一个常量数组)

是个容器,但是没有新开空间,里面有两个指针,一个指向第一个元素(常量数组的开始),一个指向最后一个元素的后一个位置(常量数组的结束),所以是8/16字节,因为是两个指针(first, last)

2、自动类型推导:

auto:

auto 关键字用于自动类型推导。编译器会根据初始化表达式自动推断出变量的类型。使用 auto 可以让代码更加简洁,例如STL容器迭代器、函数返回类型等。

缺陷:

        auto虽然用起来非常方便,但也不能滥用哦,例如在层层嵌套的函数当中,用起来是爽了,但是代码的可读性会大大下降,这时维护起来也会特别麻烦,一个变量可能得剥好几层才知道类型,还有在涉及到函数重载以及模板元编程时,容易引发错误和意外的行为。

decltype:

decltype 关键字用于查询表达式的类型。与 auto 不同,decltype 在编译时解析表达式并得到其类型,但不实际计算表达式的值。这意味着可以使用 decltype 来获得几乎任何表达式的类型,包括那些没有定义(或不可计算)的表达式。

缺陷:

        decltype的语法相对复杂一点,且在某些情况下,decltype导出的类型可能非常冗长,特别是当表达式涉及到模板类型或复杂函数时。如果在函数声明中使用decltype时,如果函数的返回类型依赖于模板参数或函数参数的类型,那么可能需要使用尾置返回类型(trailing return type)语法,这可能会使函数声明的复杂性增加。

3、final 和 override

final:

final修饰类的时候,表示这个类无法被继承、修饰虚函数时,表示这个虚函数不能被重写。

修饰类:

修饰虚函数:

override:

override 关键字用于检查派生类虚函数是否重写了基类的某个虚函数,如果没有重写编译报错。

4、默认成员函数控制:

显示缺省函数:

当你不为类定义任何构造函数时,编译器会为你生成一个默认构造函数。如果你显式地定义了其他构造函数(例如拷贝构造、移动构造还是其他自定义构造函数),但没有定义默认构造函数,编译器不会自动生成默认构造函数。如果还想编译器生成默认构造函数的话,可以在类定义中显式地使用 default 关键字来请求编译器生成默认构造函数。

删除默认函数:

如果想要一个类禁止被拷贝,在C++98当中的做法是将这个类的拷贝构造以及赋值重载直接声明为私有(private),在C++11中则更为简单一些,只需在该函数声明加上delete关键字即可

5、左值和右值:

概念补充:

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用的返回)等等,右值可以出现在赋值符号的右边,但是不能出现在赋值符号的左边,右值不能取地址。右值引用就是对右值的引用,给右值取别名。

简记:左值能出现在右边,右值不能出现在左边。

代码示例:

左值引用与右值引用:

可以先简短的记着:左值引用就是给左值取别名,右值引用就是给右值取别名!

先来谈谈简单的:左值引用:

int main()
{int a = 10;int& b = a; // b就是a的别名,其实就是a// 属于同一块地址空间:cout << &a << endl;cout << &b << endl;return 0;
}

再来谈谈右值引用:

int main()
{int x = 1, y = 2;int&& z = (x + y);string&& s1 = string("111111");string&& s2 = to_string(1234);int&& a = 10;return 0;
}

两者的联系和区别:

右值引用的本身是左值,因为只有这样才能实现移动构造和移动赋值,以此来实现资源转移,因为普通左值是没法引用右值的,必须加const,但是加了又没法实现资源的转移。

所以右值引用是有地址的:

	string&& s1 = string("111111");cout << &s1 << endl;

如果右值引用的属性是右值,那么移动构造和移动赋值,要转移资源的语法逻辑是矛盾的,右值是不能被改变的,可以理解为右值带有const属性。

诶?那再回头来看看,既然右值引用是给右值取别名,那么右值引用有地址,那么是不是右值本身是有地址的???

其实还真是,像刚才的那种右值的底层是有地址的,但是只有编译器知道,为了语法的逻辑自洽,他不会让你取得到这个地址,右值引用s1其实就是变相获取到这个地址,所以能不能取到地址不是关键,关键是资源的转移(匿名对象和临时对象都带有const属性)

一般情况下左值引用只能引用左值,不能引用右值。但是加了const的左值引用既能引用左值也能引用右值。

一般情况下右值引用只能引用右值,不能引用左值。但是右值引用可以引用move以后的左值。

move函数:将一个左值对象转化为右值引用,从而允许使用移动语义来优化资源的管理和程序的性能。

右值引用的意义:

右值引用的意义主要体现在两个方面:移动语义、完美转发。

移动语义:

1、资源所有权转移:在C++中,类的右值通常是一个临时对象,如果在表达式结束时没有被绑定到引用,就会被废弃。通过右值引用,可以在对象被废弃之前移走其资源,实现资源的再利用,再需要时,就可以避免无意义的拷贝复制操作,提高效率。

2、减少开销:被移走资源的右值在废弃时已经成为空壳,其析构的开销会大大降低。这有助于提升程序的性能,特别是在处理大型对象或资源密集型操作时。

完美转发:

这里简单讲一下,下一标题再详细叙述。

完美转发的实现依赖于右值引用。右值引用(T&&)用于绑定到即将被销毁的对象上,从而允许资源的移动而非拷贝。

在模板函数中,通过使用 T&& 作为参数类型,能够接受左值和右值作为参数。

6、完美转发:

完美转发(Perfect Forwarding)是C++11中引入的一种编程技巧,其目的是在编写泛型函数时能够保留参数的类型和值类别(左值或右值),从而实现更为高效且准确地传递参数。

完美转发允许函数模板将其接收到的参数“完美”地转发给内部调用的其他函数,这里的“完美”指的是不仅能准确地转发参数的值,还能保证被转发参数的左、右值属性不变。

省流:

完美转发就是在函数模板中,将参数转发给其他函数时,可以锁定参数的左右值属性和值类别。

因为右值引用的对象在作为实参传递时,属性会退化为左值,会直接匹配左值引用,使用完美转发可以保持它的右值属性。

这里来认识两个东西:forward函数和万能引用(T &&)

forward函数:是一个模板函数,用于实现完美转发

万能引用(T &&):既能接收左值也能接收右值。

直接上一段代码来直观感受一下:

7、lambda表达式:

lambda表达式从C++11标准开始引入的一种定义匿名函数对象的简洁方式。它可以捕获它所在作用域的变量,并可以在需要函数对象的任何地方使用,包括作为算法的一部分或作为回调函数。

基本语法:

[capture](parameters) mutable -> return_type {  // 函数体  
}
  • capture捕获列表,指定哪些外部变量在lambda函数体内是可用的。捕获列表可以是按值捕获(例如[x])或按引用捕获(例如[&x]),也可以混合使用(例如[&, x = this->x]),其中&表示按引用捕获所有外部变量,除了显式按值捕获的。=表示按值捕获所有外部变量,除了显式按引用捕获的。
  • parameters参数列表,与普通函数相同。如果lambda不接受任何参数,则可以省略括号。
  • mutable这是一个可选的说明符,表示lambda函数体内的代码可以修改按值捕获的变量。默认情况下,这些变量是只读的。
  • return_type返回类型,也是可选的。如果lambda体只有一个返回语句,且编译器能够从该语句推断出返回类型,则可以省略。如果lambda没有返回语句,则其返回类型为void

也可以就简单的记为:[](){}

其实本质就是仿函数,编译器在编译的时候就会转成仿函数,原理类似范围for

举个小例子:我给这个lambda表达式传两个值,让它返回这两个值的和给我:

补充:

int main()
{int a = 1, b = 2;// 捕捉列表auto swap1 = [a, b]() mutable // 还是传值捕捉{int tmp = a;a = b;b = tmp;};swap1();// 如果不加mutable的话a, b捕捉到的默认是const的,无法对其做出修改操作,而且·此ab非局部的那俩ab// 也就是就算带mutable修改内部也并不会改变外部printf("%d %d\n", a, b);// 引用捕捉可修改:auto swap2 = [&a, &b]() {int tmp = a;a = b;b = tmp;};swap2();printf("%d %d", a, b);// 捕捉方式还有 =, &// = 为传值捕捉所有父作用域中的变量,包括this// & 为引用捕捉所有父作用域中的变量,包括this// 还可以混合捕捉: 表示为&捕捉全局,唯独b为传值捕捉(也可以反着来)auto func = [&, b]() {};return 0;
}

8、可变参数列表:

省流:可变参数列表一种特殊的函数参数机制,允许函数接收数量不确定的参数

先来段简单的代码看看使用方法:

既然可变参数列表可以接收不确定数量的参数,那么仔细想想,好像printf函数也是如此,那么是不是就可以简单的模拟实现一下printf函数呢?

总结:可变参数列表提供了极高的灵活性和类型安全性,且支持泛型编程,但复杂性较高,可能会导致编译时间的增加和额外的性能开销。

9、包装器:

function包装器:

function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。于头文件#include <functional>

其实包装器的本质就是函数指针,可调用对象有:函数、函数对象(仿函数)、lambda表达式、绑定表达式等。

先来看一个例子:来看看下面这段代码中的函数模板会被实例化几次?

template<class F, class T>
T Test(F f, T t)
{static int x = 0;cout << "x: " << ++x << endl;cout << "x: " << &x << endl;return f(t);
}double f(double i)
{return i / 2;
}// 仿函数
struct Functor
{double operator()(double d){return d / 3;}
};int main()
{// 函数:cout << Test(f, 11.11) << endl;// 函数对象(仿函数):cout << Test(Functor(), 11.11) << endl;// lambda表达式:cout << Test([](double d) {return d / 4; }, 11.11) << endl;return 0;
}

通过结果我们可以看出来,函数模板实例化了三次(静态变量x的地址都不一样)

对于同一个模板类或模板函数,使用多种不同的类型参数去实例化它时。每次使用不同的类型参数实例化模板,编译器都会生成一份独立的模板代码。这可能导致编译时间增加、二进制文件大小膨胀,以及潜在的运行时性能问题(如指令缓存未命中增加)。

但是我只想让这个函数模板实例化一次怎么办呢?

这时就可以掏出function包装器来解决:

function用法解析:

代码结果:

这样实例化出来的就是同一份模板了(x依次递增,且为同一地址),这样通过function包装器就可以减少不必要的模板实例化,因为模板实例化多了容易导致代码膨胀,降低效率。

最重要的是:好用(滑稽)

bind(绑定):

省流:调整可调用对象的参数个数或者顺序:

完整概念:

std::bind 用于生成一个新的可调用实体(function object),这个新的可调用实体可以把它的某些(或全部)参数绑定到给定的值上。这样,当你调用这个新的可调用实体时,就不需要再为那些已经被绑定的参数提供值了。(头文件:#include <functional>

基本语法:

auto newCallable = bind(callable, arg_list, placeholders::_1, placeholders::_2, ...);
  • callable:你想要调用的函数、函数对象、成员函数指针或成员对象指针。
  • arg_list:你希望预先绑定到 callable 的参数列表。这些参数在后续调用 newCallable 时将不再需要。
  • placeholders::_1, placeholders::_2, ...:占位符,用于表示 newCallable 被调用时,需要接收的参数位置。允许保留一些参数位置以供将来调用时提供。

上个简单的代码看看:

再来看一组:也可以绑定类中的函数:

注意:

        绑定成员函数时,需要传递成员函数的地址(使用&运算符),并且还需要传递一个指向对象实例的指针(对于非静态成员函数)或对象的引用(但通常期望指针,因为bind需要能够存储这个引用所指向的对象的状态,而局部引用在函数返回后可能不再有效)。

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

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

相关文章

第132天:内网安全-横向移动Exchange服务有账户CVE漏洞无账户口令爆破

域控环境0day.org 通过网盘分享的文件&#xff1a;131-0day.org内网域环境镜像文件 链接: https://pan.baidu.com/s/1rf_gHVJSNG8PEsiSr7DFSw?pwdr5jc 提取码: r5jc 给win7设置一张nat网卡&#xff0c;其他各个主机都设置为vm2 案例一&#xff1a; 域横向移动-内网服务-Exchan…

如何快速将地址解析为经纬度坐标?

GIS数据转换器的"地址转坐标"功能&#xff0c;可以帮助用户将地址文本快速转换为对应的经纬度坐标&#xff0c;广泛应用于地图定位、数据分析、GIS项目、在线导航、城市规划、紧急服务以及科学研究等多个领域&#xff0c;极大地提高了地理信息处理的效率和准确性。下…

【题解】—— LeetCode一周小结32

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结31 5.不含连续1的非负整数 题目链接&#xff1a;600. 不含连续…

C++的序列容器——数组

前言&#xff1a; 这篇文章我们就开始新的章节&#xff0c;我们之前说的C/C的缺陷那部分内容就结束了。在开始新的章之前我希望大家可以先对着题目思考一下&#xff0c;C的容器是什么&#xff1f;有什么作用&#xff1f;下面让我们开始新的内容&#xff1a; 目录 前言&#x…

Golang | Leetcode Golang题解之第343题整数拆分

题目&#xff1a; 题解&#xff1a; func integerBreak(n int) int {if n < 3 {return n - 1}quotient : n / 3remainder : n % 3if remainder 0 {return int(math.Pow(3, float64(quotient)))} else if remainder 1 {return int(math.Pow(3, float64(quotient - 1))) * …

简简单单用用perf

实践前提&#xff1a;正确安装 perf 和 FlameGrap。若没安装&#xff0c;心领神会亦可。 1 示例程序 #define m_loop() ({ for(int i0; i < 1000000; i); })void fb(void) {m_loop(); }void fj(void) {fb(); }void fy(void) {m_loop(); }void loop(void) {for (;;) {fy();…

WPF动画

补间动画&#xff1a;动画本质就是在一个时间段内对象尺寸、位移、旋转角度、缩放、颜色、透明度等属性值的连续变化。也包括图形变形的属性。时间、变化的对象、变化的值 工业应用场景&#xff1a;蚂蚁线、旋转、高度变化、指针偏移、小车 WPF动画与分类 特定对象处理动画过…

xss.function靶场(easy)

文章目录 第一关Ma Spaghet!第二关Jefff第三关Ugandan Knuckles第四关Ricardo Milos第五关Ah Thats Hawt第六关Ligma第七关Mafia第八关Ok, Boomer 网址&#xff1a;https://xss.pwnfunction.com/ 第一关Ma Spaghet! 源码 <!-- Challenge --> <h2 id"spaghet&qu…

【精选】基于Python大型购物商城系统(京东购物商城,淘宝购物商城,拼多多购物商城爬虫系统)

目录&#xff1a; 目录&#xff1a; 系统介绍&#xff1a; 系统开发技术 Python语言 Django框架简介 MySQL数据库技术 B/S架构 系统设计 系统总体设计 系统详细界面实现&#xff1a; 系统测试 测试目的 测试用例 本章小结 参考代码&#xff1a; 为什么选择我&…

Ubuntu中编译使用ANTs(医学图像配准)含github无法访问问题解决

目录 第一步、修改hosts文件 1.打开https://github.com.ipaddress.com/ 2.打开https://fastly.net.ipaddress.com/github.global.ssl.fastly.net#ipinfo 3.打开hosts文件&#xff0c;并在文件末尾添加如下内容 第二步、编译ANTs 1&#xff09;首先安装git、cmake以及c编译…

如何在桌面同时展示多个窗口

一、实现2分屏显示 win箭头 二、实现3分屏显示 1. 在实现2分屏显示的基础上&#xff0c;再次点击箭头图标&#xff0c;这次选择屏幕的上方或下方。 2. 点击后&#xff0c;第三个窗口将会出现在你选择的区域。现在&#xff0c;你可以在三个窗口之间自由切换&#xff0c;提高工…

WebSocket协议解析与Java实践

文章目录 一、HTTP协议与HTTPS协议1.HTTP协议的用处2.HTTP协议的特点3.HTTP协议的工作流程4.HTTPS协议的用处5.HTTPS协议的特点6.HTTPS协议的工作流程 二、WebSocket协议出现的原因1. 传统的HTTP请求-响应模型2. 轮询&#xff08;Polling&#xff09;3. 长轮询&#xff08;Long…

虚幻5|AI巡逻宠物伴随及定点巡逻—初步篇

一.建立AI基本三件套 1.建立AI基本三件套 二.使用AI的基本设置 1.打开我们想要用的AI宠物的蓝图&#xff0c;选中自我Actor,右侧细节处找到AI&#xff0c;选中对应的AI控制器 三.打开AI控制器 写如下 四&#xff0c;AI行为树 1.新建一个任务&#xff0c;命名含巡逻二字即可…

一文读懂 服务器

一文读懂 服务器 马上就是毕业季了&#xff0c;做好的毕设不免上云服务器来演示一下&#xff0c;让自己答辩时加分。但相信很多小伙伴对服务器没有一个实体的概念&#xff0c;不明白什么是服务器&#xff0c;和平时使用的计算机又有什么区别。在网络上&#xff0c;经常看见的什…

PHP安全开发

安全开发 PHP 基础 增&#xff1a;insert into 表名(列名 1, 列名 2) value(‘列 1 值 1’, ‘列 2 值 2’); 删&#xff1a;delete from 表名 where 列名 ‘条件’; 改&#xff1a;update 表名 set 列名 数据 where 列名 ‘条件’; 查&#xff1a;select * from 表名 wher…

Java二十三种设计模式-责任链模式(17/23)

责任链模式&#xff1a;实现请求处理的灵活流转 引言 在这篇博客中&#xff0c;我们深入探讨了责任链模式的精髓&#xff0c;从其定义和用途到实现方法&#xff0c;再到使用场景、优缺点、与其他模式的比较&#xff0c;以及最佳实践和替代方案&#xff0c;旨在指导开发者如何…

C++:平衡二叉搜索树之红黑树

一、红黑树的概念 红黑树&#xff0c; 和AVL都是二叉搜索树&#xff0c; 红黑树通过在每个节点上增加一个储存位表示节点的颜色&#xff0c; 可以是RED或者BLACK&#xff0c; 通过任何一条从根到叶子的路径上各个节点着色方式的限制&#xff0c;红黑树能够确保没有一条路径会比…

Selenium + Python 自动化测试12(unittest组织更多用例)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以独立完成自动化测试的任务。 上一篇我们讨论了unittest中test suite 的构建&#xff0c;可以测试多条测试用例。 本篇文章我们接着讲。使用discover()方法构建更多的测试用例。 1、引入需要完成的任务 上…

【网络编程】基于UDP的TFTP文件传输

1&#xff09;tftp协议概述 简单文件传输协议&#xff0c;适用于在网络上进行文件传输的一套标准协议&#xff0c;使用UDP传输 特点&#xff1a; 是应用层协议 基于UDP协议实现 数据传输模式 octet&#xff1a;二进制模式&#xff08;常用&#xff09; mail&#xff1a;已经不再…

Linux进程间通信学习记录(IPC 机制、共享内存以及信号灯集)

0.System V IPC机制&#xff1a; ①.IPC对象包含&#xff1a;共享内存、消息队列和信号灯集。 ②.每个IPC对象有唯一的ID。 ③.IPC对象创建后一直存在&#xff0c;直到被显示地删除。 ④.每一个IPC对象有一个关联的KEY。&#xff08;其他进程通过KEY访问对应的IPC对象&#xff…