C++ 11 的新增特性

news2024/11/16 9:21:28

一.列表初始化

1.1 { }初始化

        在C++ 11 中扩大了 大括号{ } 的使用范围,我们可以使用大括号初始化内置类型对象和自定义类型对象,可以在使用时加上 等于= ,不加也可以,但是还是建议加上。

        在初始化对象时我们就可以像以下方式初始化。

#include<iostream>
using namespace std;
struct point
{
	point(int val_1, int val_2)
		:_val_1(val_1)
		,_val_2(val_2)
	{

	}
	int _val_1;
	int _val_2;
};

int main()
{
	int x1 = 10;
	int x2{ 11 };
	int a1[10] = { 1 };
	int a2[10]{ 1,2,3,4 };

	point b1(1,2);
	point b2{ 1,2 };

    point * pp = new point[2]={{1,1},{2,2}};

}

1.2 std::initializer_list 容器

当我们在使用以下的方式进行初始化时,编译器会在 定义x1对象时报错,这时为什么呢。

struct Point
{
    int _x;
    int _y;
};

int main()
{
    Point x1 {1,2,3};
    vector<int> x2 ={1,2,3};
}

在底层中,对于C++11中的现有容器,编译器在编译时,会把 现有容器 花括号{ } 中的所有元素放入initializer_list  容器中,然后将initializer_list中的元素一个个取出来,再对目标容器进行初始化操作。

二.声明

2.1 decltype

auto类型可以自动的推演对象的类型,decltype函数也有差不多相同的功能,但是他俩不同的点就在于用的场景不太相同,如下图所示

在定义变量时,auto可以自动的推导变量的类型,但是在使用函数进行实例化的时候auto就没有办法使用了,所以这个时候我们会是用decltype函数。

注意在decltype函数的括号中一定要写一个变量或者对象。

2.2 nullptr

 在C++ 98 和 C 语言中 NULL一直是使用宏替换来实现的,只要在程序中出现了null就会被编译器替换成 0 ,这么写在一些时候会带来一些bug,因为 0 可以是一个指针常量或者是一个整形常量,所以C++ 中新增了 nullptr 用来表示空指针。

三.左值、右值引用

3.1 概念

        和 左移右移的概念一样,这里的左值和右值并不是单单的代表着一个数值在等号的左边或者在等号的右边。而代表这其他意思

        左值:代表了一个变量、对象、指针,等可以被修改的对象,我们可以获取其地址,并且一般可以被赋值。

        右值:代表一个数据的表达式(字面量、表达式返回值、函数返回值等),不可以对其取地址。所谓左值引用就是左值的别名,右值引用就是右值的别名。

3.2 区别

  1.左值引用:

 (1)左值引用只能引用左值,不能引用右值

 (2)但是const 类型的左值引用既可以引用左值也可以引用右值。

        

2.右值引用

(1)只能引用右值不能引用左值

(2)右值可以引用std::move()后的左值

3.3 右值引用的意义 

1.减少反复拷贝的次数

string func()
{
    string str("Hello world");
    return str;
}

int main()
{
    string ret;
    ret = func();
    return 0;
}

        以上的代码在调用func()函数时,构建str 对象时调用了一次构造函数,然后在使用return语句的时候编译器创建了一个临时变量其值和str的内容一样,main函数中的ret在接受 func()函数的返回值时又调用了拷贝构造。

        这个程序一共调用了两次构造函数一次拷贝构造函数,这个过程无疑是造成很大时间和空间资源浪费的。

        那么以下的方式就是让主函数的ret直接获取到 str 的资源,从而节省空间和时间。

// 移动构造
string(string&& s)
	:_str(nullptr)
	, _size(0)
	, _capacity(0)
{
	cout << "string(string&& s) -- 移动语义" << endl;
	swap(s);
}
// 移动赋值
string& operator=(string&& s)
{
	cout << "string& operator=(string&& s) -- 移动语义" << endl;
	swap(s);
	return *this;
}

这里在构造str对象时,会采用这里的移动构造的方式,首先构造一个string类型的对象,并且初始化,s是Hello world字符串的右值引用,等到string对象构建完毕,就把 s 中的资源全部换给了这里this指针指向的对象了str,随后的return 还是会创建一个临时对象只不过这个对象是const string类型的临时变量具有常性(将亡值)编译器会继续调用移动构造函数。

        最后ret = func()时,会调用这里的移动赋值从而达到节省空间的作用。因为本身swap的交换是不需要付出什么代价的。

以上的写法其实只是为了说明移动构造和移动构造的原理,真正的程序不需要这么写,因为编译器会自动的进行优化的操作(只要编译器识别到了需要连续调用构造和拷贝构造时就会直接进行移动构造的操作)

3.4 C++ 11 中的新增接口

C++ 11 中新增了右值引用的方式来进行移动拷贝,每当识别到右值或者将亡值时就使用移动构造来减少深拷贝的发生。 

3.5 将亡值和纯右值

纯右值:内置类型的右值

将亡值:自定义类型的右值2

3.6 完美转发

template<class T>
void Prefect_Forward(T&& t)
{
    fun(t);
}

在模板中的 T&& 代表的是完美转发,并不是单单代表右值引用,而代表的是右值引用,它既能接受左值又能接受右值。在这里如果接受到的值是左值的话也可以称这种现象为引用折叠。

template<class T>
void Prefect_Forward(T&& t)
{
    fun(t);
}
void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }

template<typename T>
void PerfectForward(T&& t)
{
	Fun(t);
}

int main()
{
	PerfectForward(10);           // 右值

	int a;
	PerfectForward(a);            // 左值
	PerfectForward(std::move(a)); // 右值

	const int b = 8;
	PerfectForward(b);      // const 左值
	PerfectForward(std::move(b)); // const 右值
	return 0;
}

        但是以上这种写法的结果全都会调用到左值引用的函数上,因为 T&& 虽然既可以接受左值又可以接受右值,但是T&& 本身的属性是左值,这就导致我用 t 去调用函数时,发去的参数全都是左值。

        为什么这里的 T&& 类型的对象是左值属性的呢,因为不管是左值还是右值引用都是需要更改被引用类型对象的参数的,右值的属性的对象其数据都是无法修改的,所以这里T&&是左值的属性。

        那么为了让 T&& 类型的对象去代表被引用对象的属性我们就需要用到完美转发 forward 函数,该函数让被T&&引用的对象保持自己原本的属性(左值或右值)

将代码更改为如下所示 

template<class T>
void Prefect_Forward(T&& t)
{
    forward<T>(t);
}
void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }

template<typename T>
void PerfectForward(T&& t)
{
	Fun(t);
}

int main()
{
	PerfectForward(10);           // 右值

	int a;
	PerfectForward(a);            // 左值
	PerfectForward(std::move(a)); // 右值

	const int b = 8;
	PerfectForward(b);      // const 左值
	PerfectForward(std::move(b)); // const 右值
	return 0;
}

 四.类的新功能

之前在介绍类时,我们知道编译器会给一个类自动生成6种默认的成员函数

        1.构造函数        2.析构函数        3.拷贝构造

        4.赋值重载        5.取地址重载        6.const 取地址重载

C++ 11 中又新增了俩函数分别是 移动构造函数移动复制运算符重载

注意:

(1)如果我们自己没有实现移动构造、析构、拷贝、拷贝赋值重载的任意一个函数,编译器自己就会生成一个默认的移动构造和移动赋值。

(2)可以使用default关键字强制编译器自己生成默认函数

(3)可以使用delete关键字强制编译器不生成默认函数。

五. lambda 表达式

以下代码中定义了一个商品属性,我们想要按照商品的价格排序时,我们可以自己写一个仿函数来进行排序。

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
struct Goods
{
	Goods(string name, double cost, int evaluate)
		:_name(name)
		, _cost(cost)
		, _evaluate(evaluate)
	{

	}
	string _name;
	double _cost;
	int _evaluate;
};
struct Good_Sort_Less
{
	bool operator()(const Goods first, const Goods second)
	{
		return first._cost > second._cost;
	}
};
int main()
{
	vector<Goods> goodslist = { {"麦当劳",50,4},{"袁记云饺",30,5},{"肯德基",60,3} };
	cout << "排序前:	" << endl;
	for (auto e : goodslist)
	{
		cout << e._name << " 价格		" << e._cost << "	评价星级 " << e._evaluate << endl;
	}

	sort(goodslist.begin(), goodslist.end(), Good_Sort_Less());

	cout << "排序后:" << endl;
	for (auto e : goodslist)
	{
		cout << e._name << " 价格		" << e._cost << "	 评价星级 " << e._evaluate << endl;
	}
}

但是仿函数有的时候写的太烦了,C++就借鉴了python的lambda表达式,我们可以把代码修改为如下所示

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
struct Goods
{
	Goods(string name, double cost, int evaluate)
		:_name(name)
		, _cost(cost)
		, _evaluate(evaluate)
	{

	}
	string _name;
	double _cost;
	int _evaluate;
};
//struct Good_Sort_Less
//{
//	bool operator()(const Goods first, const Goods second)
//	{
//		return first._cost > second._cost;
//	}
//};
int main()
{
	vector<Goods> goodslist = { {"麦当劳",50,4},{"袁记云饺",30,5},{"肯德基",60,3} };
	auto Good_Sort_Less = [](const Goods first, const Goods second) {return first._cost > second._cost; };
	cout << "排序前:	" << endl;
	for (auto e : goodslist)
	{
		cout << e._name << " 价格		" << e._cost << "	评价星级 " << e._evaluate << endl;
	}

	sort(goodslist.begin(), goodslist.end(), Good_Sort_Less);

	cout << "排序后:" << endl;
	for (auto e : goodslist)
	{
		cout << e._name << " 价格		" << e._cost << "	 评价星级 " << e._evaluate << endl;
	}
}

lambda表达式的书写表达形式如下所示

[capture list] (parameter list) mutable -> return type { function body }

这图我偷的这个哥们的博客深入浅出 C++ Lambda表达式:语法、特点和应用_c++ lamda函数作为函数参数-CSDN博客 

        这里可以把 lambda 表达式看成一个语法糖,在C++中其实就是拿仿函数实现的,其中编译器会把parameter list 里面的变量都定义成成员变量,把函数体function body 定义成仿函数中的()运算符重载里面函数体的内容。

        mutable 可以看成把类中的成员变量使用const修饰的作用。

        一般的都会使用auto类型的变量去接受lambda表达式,然后再通过这个auto 类型的对象对lambda表达式来进行调用。

捕获列表说明:
捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用。

[var]:表示值传递方式捕捉变量var
[=]:表示值传递方式捕获所有父作用域中的变量(包括this)
[&var]:表示引用传递捕捉变量var
[&]:表示引用传递捕捉所有父作用域中的变量(包括this)
[this]:表示值传递方式捕捉当前的this指针

注意:
a. 父作用域指包含lambda函数的语句块
b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量在这里插入代码片
[&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量
c. 捕捉列表不允许变量重复传递,否则就会导致编译错误。
比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复。
d. lambda表达式之间不能相互赋值,即使看起来类型相同,底层是不同的类类型。

六.包装器

function 包装器是C++中functional头文件中的一个类模板。

我们在 定义完这里以后可以传输函数指针、仿函数、lambda 给这个包装器,都可以

甚至可以这么整

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何用Chatgpt制作流程图呢?

小说推文—— AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频百万播放量https://aitools.jurilu.com/流程图的本质&#xff0c;是对文本信息的整合组织&#xff0c;是对逻辑关系的可视化呈现。而大语言模型非常擅长从给定的…

C++策略模式:萧炎打架~

目录 策略模式步骤例子&#xff1a;萧炎使用技能打架给出UML图1&#xff1a;定义技能策略2&#xff1a;实现技能策略3&#xff1a;定义萧炎类4&#xff1a;萧炎遇到强劲的敌人5&#xff1a;战斗过程 策略模式 策略模式是一种行为设计模式&#xff0c;它定义了一系列算法&#…

学姐说,WebGIS面试八股文不会也得背!会!

本文全是干货&#xff0c;内容来一线GIS开发工程师&#xff0c;目前是中地数码集团、新中地GIS开发特训营高级讲师&#xff0c;从事GIS软件开发工作8年&#xff0c;拥有丰富的软件开发和项目研发经验&#xff0c;对webGIS、桌面GIS开发有较深研究&#xff0c;深谙GIS开发面试的…

玩转单例模式

目录 1. 饿汉式 2. 懒汉式 3. volatile解决指令重排序 4. 反射破坏单例模式 5. 枚举实现单例模式 6. 枚举实现单例模式的好处 7.尝试反射破坏枚举 所谓单例模式&#xff0c;就是是某个类的实例对象只能被创建一次&#xff0c;单例模式两种实现&#xff1a;饿汉式和懒汉…

unity程序简易框架

1. 框架基本结构 2. 单例模式基类模块 2.1 BaseManager.cs using System.Collections; using System.Collections.Generic; using UnityEngine;public class BaseManager<T> where T:new() {private static T instance;public static T GetInstance(){if (instance == …

直播预约|2024 乐鑫科技全球开发者大会亮点揭秘

时隔一年&#xff0c;2024 乐鑫科技全球开发者大会将在 9 月 3-5 日如约而至。这一年&#xff0c;人工智能给物联网领域带来了哪些变化&#xff1f;乐鑫在 AIoT 领域实现了哪些新突破&#xff1f;ESP-IDF 经过升级后增添了哪些新功能&#xff1f;ESP32-P4、ESP32-C6 迎来了怎样…

C语言指针详解-上

C语言指针详解-上 前言1.指针的基本概念1.1指针是什么1.2指针的声明与初始化1.3取地址符&和解引用符*& 运算符用于**获取变量的地址*** 运算符用于访问指针指向的值 2.指针的类型常见数据类型的指针指针与数组、字符串数组指针结构体指针函数指针二级指针void指针 3.指…

多级评论的实现,评论回复功能(两层型)

前言&#xff1a; 技术栈&#xff1a;springboot mysql mybatis 比着写一遍&#xff0c;你也一定会实现多级评论的功能&#xff0c;简单易上手&#xff01; 1.效果 整体的结构只有两层&#xff0c;但是确实现了评论回复功能 [ { "id": 2, "userId": …

让JMeter测试数据生成更容易

让JMeter测试数据生成更容易 背景&#xff1a; 在软件测试过程中&#xff0c;为了确保系统的稳定性和可靠性&#xff0c;需要对各种场景进行全面的测试。而不同的场景往往需要各种各样的测试数据&#xff0c;这些数据需要具有一定的真实性和多样性&#xff0c;以模拟实际使用…

零基础小白实现C#调用halcon dll的过程,并测试程序证明C#halcon联合开发成功

本篇将介绍零基础小白实现C#调用halcon dll的过程&#xff0c;同时这其中涉及到很多知识&#xff0c;务必将HDevelop和VisualStudio安装成功。下面我将详细阐述C#调用halcon dll的过程&#xff0c;你的点赞和评论是我一直前行的动力。 1. C#调用Halcon DLL的过程 要在C#中调用…

选择TPM管理咨询公司,这几点是关键!

在这个日新月异的商业时代&#xff0c;企业的竞争力不仅体现在产品和服务上&#xff0c;更在于其内部管理的精细化与高效化。TPM作为提升企业综合生产效率的利器&#xff0c;正逐步成为众多企业转型升级的必然选择。然而&#xff0c;如何在众多TPM管理咨询公司中慧眼识珠&#…

嘉盛:股指、国债及商品期货分析

股指展望中证全指在2024年下半年可能迎来约20%的上涨空间。尽管市场估值较低&#xff0c;风险溢价仍维持在高位&#xff0c;这提升了指数的配置性价比。预计无风险利率将继续维持在较低水平&#xff0c;对中证全指估值产生积极影响。盈利方面&#xff0c;预计下半年中证全指EPS…

【广东】邀您共赴纷享销客生态伙伴大会

在数字化浪潮的驱动下&#xff0c;CRM行业正迎来前所未有的创新机遇。作为CRM领域的引领者&#xff0c;纷享销客特别举办“纷享销客2024生态伙伴大会&#xff08;广东站&#xff09;”。我们诚挚邀请各位生态伙伴莅临现场&#xff0c;共同探讨SaaS CRM行业的最新趋势&#xff0…

haproxy负载均衡+mysql读写分离

haproxy负载均衡 [roothaproxy01 ~]# yum -y install ntpdate [roothaproxy01 ~]# yum -y install ntp [roothaproxy01 ~]# systemctl start ntpd 安装haproxy [roothaproxy01 ~]# yum -y install ntpdate 配置文件的地址 [roothaproxy01 ~]# rpm -ql haproxy [roothap…

美摄科技携手蔚来汽车,共创用户出行新体验!

7月27日&#xff0c;蔚来举办了以 AI 为主线的 “NIO IN 2024 蔚来创新科技日”&#xff0c;此次活动展示了蔚来在智能电动汽车领域最新探索与成果&#xff0c;为中国乃至全球的智能汽车行业树立了新的标杆。当晚&#xff0c;央视《主播说联播》以“中国智能车在全球竞争的另一…

MIT6.s081 2021 Lab Multithreading

Uthread: switching between threads 思路 xv6 已经实现了进程的切换机制&#xff0c;本实验要求参考进程的切换&#xff0c;实现一个用户态线程的切换。 要实现线程切换&#xff0c;必然涉及上下文&#xff0c;即寄存器的保存和恢复&#xff0c;那么需要保存哪些寄存器&…

建筑工程项目管理系统-计算机毕设Java|springboot实战项目

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

建筑工地安全检查

在现代化的建筑工地中&#xff0c;安全始终是至关重要的核心问题。随着科技的不断进步&#xff0c;凡尔码建筑工地安全系统应运而生&#xff0c;灵活根据施工现场管理要求搭建建筑工地安全系统各个模块&#xff0c;为施工安全带来了全新的保障。 如何注册建筑工地安全系统后台…

自动打电话软件给企业带来了什么?

使用机器人外呼系统肯定都是想要给自己企业带来好处和解决问题的&#xff0c;想让自己的企业有所改变&#xff0c;有更好的发展&#xff0c;所以才会选择使用机器人外呼系统。而它也确实没让大家失望&#xff0c;使用了机器人外呼系统之后确实有许多企业发生了很大改变和进步&a…

鲁棒性目标检测 TOP2 方案分享

关联比赛: ACM MM2021 安全AI挑战者计划第七期&#xff1a;鲁棒性标识检测 ACM MM2021 鲁棒性目标检测比赛 TOP 2 方案 ​ 赛题背景 在商品知识产权领域&#xff0c;知识产权体现为在线商品的设计和品牌。不幸的是&#xff0c;在每一天&#xff0c;存在着非法商户通过一些…