可变参数模板

可变参数模板对参数进行了高度泛化,可以表示任意数目、任意类型的参数:
语法为:在class或者typename后面带上省略号。

Template<class ... T>
void func(T ... args)
{//
}

T:模板参数包,args叫做函数参数包
省略号作用:
1、声明一个包含0到任意个模板参数的参数包
2、在模板定义的右边,可以将参数包展开一个个独立的参数
c++11可以使用递归函数的方式展开参数包,获得可变参数的每个值。不过这个需要提供一个参数包展开函数和一个递归终止函数。
参数Args…在展开的过程中会递归调用自己,每调用一次,参数包中的参数就会少一个,直到所有参数都展开为止。

右值引用

1、临时对象的深拷贝

一个带有堆内存的类,必须提供一个深拷贝的拷贝函数。因为默认的拷贝构造函数是浅拷贝,会发生指针悬挂问题(两个对象的两个指针指向同一块内存,当函数作用结束后,两个对象分别调用析构函数,错误地将一块内存区析构两次)。
提供深拷贝地构造函数可以保证正确,但是会造成额外地性能损耗。

GetA函数会返回临时变量,然后通过这个临时变量拷贝构造一个新的对象a,临时变量在拷贝构造完成之后就销毁了。如果这个堆内存很大地话,拷贝构造的代价很大。也就是说每次产生临时变量都会造成额外地性能损失。

2、移动构造函数解决问题

A(A&& a) :m_ptr(a.m_ptr){a.m_ptr = nullptr;cout << "move construct" << endl;}

move construct这个构造函数是移动构造函数,它的参数是一个右值引用类型A&&。
它仅仅是将指针的所有者转移到了另一个对象上,同时将参数对象a的指针置空。也就是说,这里仅仅做了浅拷贝,从而避免了临时变量的深拷贝问题。

为什么能够匹配到这个构造函数呢?
这个构造函数只能够接受右值参数,而函数的返回值就是右值,所以就会匹配到这个构造函数。A&&看作临时值的标识。

对于临时值我们仅仅需要做浅拷贝即可,无需再做深拷贝,从而解决了临时变量拷贝构造产生的性能损失问题。这就是移动语义

3、左值借助移动语义优化性能

我们可以使用std::move将左值转换为右值引用。
move是将对象资源的所有权从一个对象转移到另一个对象,只是转移,没有内存的拷贝,这就是所谓的move语义。
通常这样使用:
使用move将左值转换成右值引用。应用移动语义,调用移动构造函数。
我们需要记住:
如果一个对象内部有较大的内存或者动态数组,就很有必要写move语义的拷贝构造函数和赋值函数,避免无所谓的深拷贝,以提高性能

左值引用和右值引用本质作用都是减少拷贝提高效率。
右值引用可以弥补左值引用不足的地方,右值引用做参数和做返回值减少拷贝的本质是利用了移动构造和移动赋值。
左值引用:
做参数: void func(T x) -> void func(T& x) 减少了传参过程中的拷贝
做返回值: T func() -> T& func() 减少返回过程中的宝贝(返回对象除了作用域不存在了就不能使用传引用了)
右值引用:
做参数: void func(T&& x) : 使func内部不再将x拷贝构造到容器空间上,而是采用移动构造
做返回值:利用移动构造减少拷贝。

4、完美转发

右值引用会在第二次之后的参数传递过程中右值属性丢失,在下一层调用中会识别成左值。
C++11引入完美转发的概念,完美转发是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数

#include<iostream>
using namespace std;
void Fun(int& x)
{cout << "左值引用" << endl;
}
void Fun(int&& x)
{cout << "右值引用" << endl;
}template<typename T>
void PerfectForward(T&& t)
{Fun(std::forward<T>(t));
}int main()
{//右值引用PerfectForward(10);int a;//左值引用PerfectForward(a);//右值引用PerfectForward(std::move(a));return 0;
}

lambda表达式

lambda表达式定义了一个匿名函数,并且可以捕获一定范围内的变量,定义如下:
[capture] (params)mutable->return_type{statement}

[capture] :捕获列表,捕获上下文变量以供lambda使用。编译器根据[]符号来判断接下来的代码是否是lambda函数。
(params):参数列表,与普通函数的参数列表一致,如果不需要传递参数,可以连同括号一起省略
mutable:修饰符,默认情况下lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略
return_type:返回值类型
{statement}:函数体,内容与普通函数一样,除了可以使用参数之外,还可以使用所捕获的变量。

lambda表达式与普通函数最大的不同就是它可以通过捕获列表访问一些上下文的数据。

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

lambda的类型被定义为“闭包”的类,通常用于stl库中。在某些场景下用于简化仿函数的使用,同时lambda作为局部函数,也会提高复杂代码的开发速度。可以在函数内部重用代码,不需要费心设计接口。
下面是示例代码:

#include<iostream>
using namespace std;int main()
{int a = 0, b = 1;//实现a+b的lambda表达式auto add1 = [](int x, int y)->int {return x + y;};cout << add1(a, b) << endl;auto add2 = [a, b]()->int {return a + b;};cout << add2() << endl;cout << a << " " << b << endl;//实现a和b的交换auto swap1 = [](int& x, int& y){int tmp = x;x = y;y = tmp;};swap1(a, b);cout << "swap1() " << a << " " << b << endl;auto swap2 = [&a, &b]()mutable{int tmp = a;a = b;b = tmp;};swap2();cout << "swap2() "<< a << " " << b << endl;return 0;
}

可变参数模板、右值引用带来的移动语义完美转发、lambda表达式的理解相关推荐

  1. 右值引用带来的效率提升(C++11)

    文章目录 一.左值引用和右值引用 二.C++11区分左值和右值的语法设计意义--对象的移动构造和移动赋值 场景分析1: C++11之前 C++11之后 场景分析2: 函数std::move 右值引用的 ...

  2. 右值引用 移动构造函数 移动语义

    一篇讲的很好的博客:https://www.jianshu.com/p/d19fc8447eaa 左值 右值: 看能不能对表达式取地址,如果能,则为左值,否则为右值. 将亡值和纯右值: 左值 右值: ...

  3. [译]详解C++右值引用

    2019独角兽企业重金招聘Python工程师标准>>> C++0x标准出来很长时间了,引入了很多牛逼的特性[1].其中一个便是右值引用,Thomas Becker的文章[2]很全面的 ...

  4. C++新特性探究(13.6):右值引用再探究

    相关博文: C++新特性探究(十三):右值引用(r-value ref)&&探究 C++新特性探究(十六):move constructor移动构造 C++新特性探究(13.5):右值 ...

  5. 详解 C++ 左值、右值、左值引用以及右值引用

    文章目录 一.左值和右值 1.左值 2.右值 3.总结 二.左值引用和右值引用 1.左值引用 2.右值引用 3.对比与总结 三.左值引用的使用场景及实际意义 1.使用场景 2.实际意义 3.短板 四. ...

  6. C++面试 左值、右值、左值引用、右值引用

    1.左值和右值 左值(left-values),缩写:lvalues  ,located value 可定位值,其含义是可以明确其存放地址的值,更确切说对其的使用是基于地址 右值(right-valu ...

  7. 移动语义-右值引用-完美转发-万字长文让你一探究竟

    C++ 右值引用 block://6984617523950616580?from=docs_block&id=ce31003ceb5efb1f7a7c0a5fbe6cb60191627a38 ...

  8. C++11中的右值引用

    http://www.cnblogs.com/yanqi0124/p/4723698.html 在C++98中有左值和右值的概念,不过这两个概念对于很多程序员并不关心,因为不知道这两个概念照样可以写出 ...

  9. C++11特性《 右值引用-<完美转发>、lambda表达式》

    1.右值引用 1.1移动语义 如果一个类中涉及到资源管理,用户必须显式提供拷贝构造.赋值运算符重载以及析构函数,否则编译器将 会自动生成一个默认的,如果遇到拷贝对象或者对象之间相互赋值,就会出错,比如 ...

最新文章

  1. SAP MM 移动类型343不开放给业务人员之思考
  2. CentOS 6.3下源码安装LAMP(Linux+Apache+Mysql+Php)环境
  3. 1.9 实例:截取新闻标题
  4. jquery ajax html方法吗,jQuery ajax方法
  5. leetcode-49-字母异位词分组(神奇的哈希)
  6. 那些开发《虚拟光驱》的人们
  7. VS系列IDE(2005、2008等)下使用cppunit的方法及使用示例
  8. 二叉链表和职工管理系统结合_职工信息管理系统单链表实现C语言源程序
  9. 知识、经验的漏洞还有很多很多
  10. linux PS1 变量设置
  11. 2022手机号段大全、归属运营商整理—2022.01.04更新(包含三大运营商)
  12. python编写beta计算器_|python编写计算器
  13. 如何为BLE 设备添加OTA DFU 空中升级服务(下)?
  14. 基于openstack的云桌面开源框架
  15. 2021开年巨作!JDBC连接数据库工具类!
  16. css书写顺序规范---规范书写很重要
  17. 汉字转换拼音首字母(可以处理部分多音字)
  18. \t\t把超星图书虚拟打印为PDF格式,实现永久阅读
  19. 牛客网判断推理练习题
  20. Java程序经编译后会产生什么

热门文章

  1. linux单网卡多拨Adsl,ROS单线多拨pppoe
  2. vue 子父组件周期顺序_父组件和子组件生命周期钩子执行顺序是什么?
  3. 2022将至,前端程序员们应该一起放个烟花庆祝一下,走起
  4. 某大厂JVM常见面试题(二)吐血整理
  5. oracle 库存管理系统,库存管理系统
  6. mysql 替代like_mysql用instr替代like查询
  7. 箱式图 添加异常值平均值_什么是脏数据?怎样用箱形图分析异常值?终于有人讲明白了...
  8. 使用data-自定义数据及如何获取该值
  9. 课时77.序选择器(掌握)
  10. 使用Gitolite搭建Gitserver