「C++」C++11新特性

在这里插入图片描述

💻文章目录

  • 📄前言
  • 右值引用
    • 概念
    • 右值引用的意义
    • 移动构造和移动赋值
    • 完美转发
  • lambada表达式
  • 包装器
    • function包装器
    • bind包装器
  • 📓总结


📄前言

C++标准10年磨一剑,于2011年迎来了它真正意义上的第二个标准,C++11能更好地适用与系统开发和库开发,语法与更加的繁华与简单化,本篇文章将重点介绍其中的右值引用lambda表达式包装器

右值引用

概念

要讨论什么是右值引用前,得要分清什么是左值,什么是右值。

左值一般为位变量名或解引用的指针,左值可以出现在赋值符号的左边,也可以出现在赋值符号的右边。

右值一般位常量,表达式返回值,函数返回值,右值可以出现在赋值符号的右边,但不能出现在符号的左边,且右值不能取地址 ,右值引用就是对右值的引用,起别名。

下面的左值和右值的对比

int main()
{
	/*左值*/
	int i = 0, j = 0;
	const int n = 123;
	const char* str = "abcd";
	
	/*左值引用*/
	int& ii = i;
	const char*& rstr = str;
	const int& nn = n;

	/*右值*/
	10;
	i + n;
	max(n, j);

	/*右值引用*/
	int&& rri = 12;
	double&& rr2 = 12.12 / 1.1;
	
	return 0;
}

右值引用的意义

左值引用其最大用途就是可以不用拷贝参数直接将数值传给函数,从而我们再也不需要担心传值拷贝的效率低下了。

注意:move函数可以使左值强行转化成右值

vector<int>&& test(vector<int>&& nums)	//这里右值变成了左值
{
    printf("%p\n", &nums);	
    sort(nums.begin(), nums.end(), greater<int>());

    return std::move(nums);	//转化成右值
}

int main()
{
    vector<int> nums {1,2,3,4,5,6,7,8,9};
    printf("%p\n", &nums);
    test(std::move(nums));	//强制转化成右值
    printf("%p\n", &nums);
    
    return 0;
}

结果:
0x7ffc04e86810
0x7ffc04e86810
0x7ffc04e86810

移动构造和移动赋值

移动构造和移动赋值C++11为类新增的内置函数,在类传值返回的时候可以将类内资源转移到临时对象上,避免了深拷贝造成的资源浪费。

string(string&& s)	//移动构造
{
	cout << "string(string&& s) -- 移动拷贝" << endl;

	swap(s);
}
//移动赋值
string& operator=(string&& s)
{
	cout << "string& operator=(string&& s)-- 移动赋值" << endl;

	swap(s);
	return *this;
}

注意:最新的编译器会把优化开的比较高,不好用与学习移动语义

  • gcc关闭优化:-fno-elide-constructors

完美转发

完美转发指的让数值保持其原本的属性,不因为传参而从右值转化成左值

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(std::forward<T>(t));	//可以自己尝试如果不使用完美转发的结果。
}

lambada表达式

lambda的书写格式[捕捉列表] (参数列表) mutable -> return-type { 函数体 }

1.[捕捉列表]:捕捉列表可以捕捉上下文的变量供lambda函数使用,使用 = 符号表示捕捉的变量都是传值传递,& 表示都是引用传递,并且编译器根据[ ]来判断接下来的代码是否为lambda函数。
2. (参数列表):与普通函数的参数列表一样。
3. 普通情况下,lambda函数都是一个const函数,mutable可以取消器常量性
4. {函数体}:在函数体内可以使用参数列表或捕捉列表的变量。
5. return-type:lambda表达式会自动推导返回值,所以返回类型可写可不写

样例

int main()
{

	vector<int> nums{ 1,2,3,4,5 };
	sort(nums.begin(), nums.end(), [&](int& a, int& b) { return a > b; });

	int a = 3, b = 3;	//lambda表达式也可以使用auto表达式来定义。
	auto add = [](int a, int b) { return a + b; };
	int x = add(a, b);

	return 0;
}

包装器

function包装器

function包装器是用于解决函数模板可调用的类型太多,而导致的效率低下问题。

template<class F, class T>
T useF(F f, T x)
{
	static int count = 0;
	cout << "count:" << ++count << endl;
	cout << "count:" << &count << endl;
	return f(x);
}

double f(double i)
{
	return i / 2;
}

struct Functor
{
	double operator()(double d)
	{
		return d / 3;
	}
};

int main()
{
	// 函数名
	cout << useF(f, 11.11) << endl;
	// 函数对象
	cout << useF(Functor(), 11.11) << endl;
	// lamber表达式
	cout << useF([](double d)->double{ return d/4; }, 11.11) << endl;
	
	return 0;
}

允许上面程序会发现useF函数模板实例化了三份,而包装器就可以解决这个问题。

int main()
{
	// 函数名(函数指针)
	std::function<int(int, int)> func1 = useF;
	// 函数对象
	std::function<int(int, int)> func2 = Functor;
	// lamber表达式
	std::function<int(int, int)> func3 = [](const int a, const int b)
	cout << func1(1, 2) << endl;
	cout << func2(1, 2) << endl;
	cout << func3(1, 2) << endl;

	return 0;
}

bind包装器

bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。

bind原型

// 原型如下:
template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
// with return type (2)
template <class Ret, class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);

bind可以调整函数的参数顺序

int func(int a, int b)
{
	cout << "a: " << a << endl;
	cout << "b: " << b << endl;
	return a / b;
}

int main()
{
	//_1 与 _2 是参数的顺序,在命名空间placeholders中定义。
	auto func1 = bind(func, placeholders::_2, placeholders::_1);
	cout << func1(5, 10) << endl;
}

给函数参数默认值

int func(int a, int b)
{
	cout << "a: " << a << endl;
	cout << "b: " << b << endl;
	return a / b;
}

int main()
{
	//_1 与 _2 是参数的顺序,在命名空间placeholders中定义。
	auto func1 = bind(func, 13, 6);
	cout << func1(5, 10) << endl;	//给定默认值后便不可修改。
	function<int(int, int)> func2 = bind(func, placeholders::_2, placeholders::_1);	//也可以和function一起使用
}

📓总结

📜博客主页:主页
📫我的专栏:C++
📱我的github:github

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

备忘录不小心删了怎么办?如何找回我的备忘录?

如果你的记性不太好&#xff0c;或者每天需要记住、完成的事情很多&#xff0c;那么养成随手记事的好习惯是非常有必要的。因为手机是每个成年人都会随身携带的电子设备&#xff0c;所以直接在手机上记录事情比较简单、便捷。而手机备忘录、便签、笔记等工具类软件&#xff0c;…

Docker快速理解及简介

docker快速理解及简介 1.Docker为什么出现&#xff1f; 迁移一个项目时&#xff0c;运行文档、配置环境、运行环境、运行依赖包、操作系统发行版、内核等都需要重新安装配置&#xff0c;比较麻烦。 2.Docker是什么&#xff1f; Docker是基于Go语言实现的云开源项目。解决了运行…

ToDesk优惠码来了,需要的不容错过

最近发现Todesk也有活动了&#xff0c;很多小伙伴不知道&#xff0c;除了中秋国庆双节&#xff0c;ToDesk另有专享优惠码&#xff0c;输入优惠码最高立减25元&#xff0c;即使是活动日也能折上折&#xff0c;不影响此优惠码的折扣力度&#xff01; Todesk作为国内优良的远程控制…

ssm土家风景文化管理平台源码和论文答辩PPT

摘要 土家风景文化管理平台是土家风景文化管理必不可少的一个部分。在风景文化管理的整个过程中&#xff0c;平台担负着最重要的角色。为满足如今日益复杂的管理需求&#xff0c;各类土家风景文化管理平台也在不断改进。本课题所设计的土家风景文化管理平台&#xff0c;使用jav…

LED恒流开关调节器FP7123,提供稳定电流,提升LED产品效果!

目录 一、FP7123概述 二、FP7123功能 LED恒流开关调节器FP7123的优势不仅仅在于提供稳定的电流&#xff0c;还包括以下几个方面&#xff1a; 三、应用领域 随着科技的不断发展&#xff0c;LED照明产品已经成为人们生活中不可或缺的一部分。然而&#xff0c;LED的亮度和稳定性…

mac M系列芯片安装chatGLM3-6b模型

1 环境安装 1.1 mac安装conda. 下载miniconda&#xff0c;并安装 curl -O https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh sh Miniconda3-latest-MacOSX-arm64.sh1.2 创建虚拟环境并激活 创建名为chatglm3的虚拟环境&#xff0c;python版本为3.10…

环形链表 2:找出入环的第一个节点

题目描述&#xff1a; 给定一个链表返回链表开始入环的第一个点。如果链表无环&#xff0c;则返回NULL。 为了表示给定链表中的环&#xff0c;我们使用整数pos来表示链表尾连接到链表中的位置&#xff08;索引从0开始&#xff09;。如果pos是-1&#xff0c;则在该链表中没有环。…

Autosar标准解析

AUTOSAR&#xff08; Automotive Open System Architecture &#xff09;——汽车开放系统架构&#xff0c;是一家致力于制定汽车电子软件标准的联盟&#xff08;宝马、博世、大陆、戴姆勒、福特、标志雪铁龙、丰田和大众&#xff09;&#xff0c;成立于2003年&#xff0c;是一…

关于自动化测试框架pytest的Fixture固件

什么是固件 Fixture 翻译成中文即是固件的意思。它其实就是一些函数&#xff0c;会在执行测试方法/测试函数之前&#xff08;或之后&#xff09;加载运行它们&#xff0c;常见的如接口用例在请求接口前数据库的初始连接&#xff0c;和请求之后关闭数据库的操作。 我们之前在A…

[Unity数据管理]自定义菜单创建Unity内部数据表(ScriptableObject)

Unity 在开发的时候如果数据量比较大&#xff0c;或者一部分数据需要存在云端&#xff0c;那么就需要一些数据库 轻量型到大型的包括&#xff1a; 数组-内存存储读取 列表-内存存储读取 List<T> tList new List<T>(); XML-硬盘存储读取 JSON-硬盘存储读取 …

SoC with CPLD and MCU ?

AG32 MCU 产品支持多种接口外设&#xff0c;具备与业界主流产品的兼容性&#xff0c;并内置额外的2K FPGA 可编程逻辑。 产品支持 LQFP-48&#xff0c;LQFP-64&#xff0c;LQFP-100 &#xff0c;QFN-32等不同封装。其所有可用 IO 都可以任意地进行映射和互换&#xff0c;以灵活…

2024版软件测试面试100问(答案+文档)

软件测试面试百题 1、问&#xff1a;你在测试中发现了一个bug&#xff0c;但是开发经理认为这不是一个bug&#xff0c;你应该怎样解决? 首先&#xff0c;将问题提交到缺陷管理库里面进行备案。 然后&#xff0c;要获取判断的依据和标准&#xff1a; 根据需求说明书、产品说…

二阶变系数线性微分方程

1、变量替换法 欧拉方程 是常数&#xff0c;是已知的函数。 二阶欧拉方程 (1) 当时&#xff0c;令,则 代入&#xff08;1&#xff09;中&#xff0c; .这样就把欧拉方程&#xff0c;化成了二阶常系数非齐次微分方程 当x<0时&#xff0c;令, 例题 解:令,则 代入上面的推…

Tenda 路由器 uploadWewifiPic后台RCE漏洞复现

0x01 产品简介 腾达路由器是一款高效实用的路由器,致力于为家庭用户提供舒适、便捷、自然的智慧家庭体验。简单便捷的部署在家庭中,彻底解决家庭用户的网络接入问题。 0x02 漏洞概述 腾达路由器后台 uploadWewifiPic 路由存在命令执行漏洞,攻击者可利用漏洞执行任意命令获取…

Linux入门攻坚——7、磁盘管理——文件系统挂载管理及RAID、LVM

已经安装文件系统的分区需要经过挂载才能使用。 一切文件系统的使用都是从根开始&#xff0c;根是文件系统的起始点。 计算机启动过程&#xff1a;加电自检——bootloader——kernel——rootfs——/sbin/init kernel第一步要加载根系统。 将额外文件系统与根文件系统某现存的…

D2822ML 用于便携式录音机和收音机作音频功率放大器。采用 DIP8 SOP8 封装形式

D2822ML 用于便携式录音机和收音机作音频功率放大器。采用 DIP8 SOP8 封装形式 特点: 电源电压降到 1.8V 时仍能正常工作交越失真小 静态电流小可作桥式或立体声式功放应用外围元件少通道分离度高 开机和关机无冲击噪声软限幅

JavaScript递归

前端面试大全JavaScript递归 &#x1f31f;经典真题 &#x1f31f;递归 &#x1f31f;真题解答 &#x1f31f;总结 &#x1f31f;经典真题 使用递归完成 1 到 100 的累加 &#x1f31f;递归 A recursive method is a method that calls itself. 递归调用是一种特殊的调…

Arrays类练习 - Java

案例&#xff1a;自定义Book类&#xff0c;里面包含name和price&#xff0c;按price排序(从大到小)。要求使用两种方式排序&#xff0c;有一个 Book[] books 4本书对象。 使用前面学习过的传递实现Comparator接口匿名内部类&#xff0c;也称为定制排序。可以按照price (1)从大到…

【Element】el-table组件使用summary-method属性设置表格底部固定两行并动态赋值

一、背景 需求&#xff1a;在表格账单中底部添加两行固定行&#xff0c;来统计当前页小计和总计。element ui 官网上是直接将本列所有数值进行求合操作的&#xff0c;且只有固定一行总计。目前的需求是将接口返回的数据填充到底部固定的两行中 二、底部添加两行固定行 2.1、…

CPP-SCNUOJ-Problem P20. [算法课回溯]优美的排列

Problem P20. [算法课回溯]优美的排列 假设有从 1 到 n 的 n 个整数。用这些整数构造一个数组 perm&#xff08;下标从 1 开始&#xff09;&#xff0c;只要满足下述条件 之一 &#xff0c;该数组就是一个 优美的排列 &#xff1a; perm[i] 能够被 i 整除 i 能够被 perm[i] 整…