C/C++ ③ —— C++11新特性

1. 类型推导

1.1 auto

  • auto可以让编译器在编译期就推导出变量的类型
    • auto的使⽤必须⻢上初始化,否则⽆法推导出类型
    • auto在⼀⾏定义多个变量时,各个变量的推导不能产⽣⼆义性,否则编译失败
    • auto不能⽤作函数参数
    • 在类中auto不能⽤作⾮静态成员变量
    • auto不能定义数组,可以定义指针
    • auto⽆法推导出模板参数
    • 在不声明为引⽤或指针时,auto会忽略等号右边的引⽤类型和const(常量)、volatile(易变性)限定
    • 在声明为引⽤或者指针时,auto会保留等号右边的引⽤和cv属性

1.2 decltype

  • ⽤于推导表达式类型,这⾥只⽤于编译器分析表达式的类型,表达式实际不会进⾏运算
  • decltype不会像auto⼀样忽略引⽤和cv属性,decltype会保留表达式的引⽤和cv属性
  • 对于decltype(exp),若exp是表达式,decltype(exp)和exp类型相同;若exp是函数调⽤,decltype(exp)和函数返回值类型相同;若exp是左值,decltype(exp)是exp类型的左值引⽤。
  • auto和decltype配合使用:
template<typename T, typename U>
auto add(T t, U u)->decltype(t + u){return t + u;
}

2. 范围for循环

  • 基于范围的迭代写法,for(变量:对象)表达式:
string str ("some thing");
for(char c : str) cout << c << endl;
  • 对vector中的元素进⾏遍历:
vector<int> arr(5, 100);
for(vector<int>::iterator i = arr.begin(); i != arr.end(); ++i) cout << *i << endl;
for(auto &i : arr) cout << i << endl;

3. 右值引用

3.1 左值和右值

  • 左值:可以放在等号左边,可以取地址并有名字
  • 右值:不可以放在等号左边,不能取地址,没有名字
    • 其定义形式为:Type &&var;其中 Type 表示变量的类型,var 表示变量名。
  • ++i、–i是左值,i++、i–是右值

3.2 左值引用和右值引用

  • 左值引用:
    • 左值引⽤就是对左值进⾏引⽤的类型,是对象的⼀个别名
    • 并不拥有所绑定对象的堆存,所以必须⽴即初始化。 对于左值引⽤,等号右边的值必须可以取地址,如果不能取地址,则会编译失败,或者可以使⽤const引⽤形式
  • 右值引用:
    • 右值引用所引用的对象是一个右值,右值对象是指其生命周期即将结束的对象,例如一次函数调用的返回值、临时变量等。
    • 表达式等号右边的值需要是右值,可以使⽤std::move函数强制把左值转换为右值

3.3 右值引用的使用场景

  • 以字符串类为例,假设有一个字符串对象 A,我们要把它赋值给另外一个字符串对象 B
string A = "HELLO";
string B = A;
  • 这样做的结果是,我们创建了两个相同内容但是不同地址的字符串对象,其中一个占用了额外的内存,存在性能问题。
  • 为了解决这个问题,C++11 移动语义提供了将对象 A 移动到 B 中的操作:
    • 当我们需要把一个对象赋值给另一个对象时,编译器会调用其复制构造函数或者赋值构造函数来创建一个新对象。但是,在某些情况下,复制操作会非常耗时;如果复制操作是不必要的,此时,使用移动构造函数,它不需要复制整个对象,而只是需要将原对象中的指针等资源转移到目标对象中即可,这样可以提高复制性能。
string A = "HELLO";
string B = std::move(A);
  • 上述代码就可以把对象 A 移动到 B 中,并不需要创建新的对象和分配内存。
  • 需要注意的是,只能对一个右值引用或者一个将要销毁的对象调用 std::move() 函数,否则会导致潜在的内存问题和错误。此外,在使用右值引用时,需要注意数据的生命周期问题,不要在使用后再次使用已经被移动的对象。

3.4 forward 完美转发

  • forward 完美转发实现了参数在传递过程中保持其值属性的功能,即若是左值,则传递之后仍然是左值,若是右值,则传递之后仍然是右值。
  • &&既可以对左值引用,亦可以对右值引用,但它后面的val值本身是个左值;&只能左值引用
template <class T>
void Print(T &t){ cout << "L" << t << endl; }
template <class T>
void Print(T &&t){ cout << "R" << t << endl; }template <class T>
void func(T &&t){Print(t);    Print(move(t));    Print(forward<T>(t));
}int main(){cout << "-- func(1) --" << endl;    func(1);  cout << "-- func(x) --" << endl;  int x = 10;    int y = 20;    func(x);  // x本身是左值    cout << "-- func(forward<int>(y)) --" << endl;    func(forward<int>(y)); //T为int,以右值方式转发y    cout << "-- func(forward<int&>(y)) --" << endl;    func(forward<int&>(y));    cout << "-- func(forward<int&&>(y)) --" << endl;    func(forward<int&&>(y));    return 0;
}

运行结果:在这里插入图片描述

3.5 emplace_back 减少内存拷贝和移动

  • emplace_back能就地通过参数构造对象,不需要拷贝或者移动内存,相比 push_back能更好地避免内存的拷贝与移动,使容器插入元素的性能得到进一步提升。在大多数情况下应该优先使用emplace_back来代替push_back。

4. lambda 匿名函数

  • 表示⼀个可调⽤的代码单元,没有命名的内联函数,不需要函数名因为我们直接(⼀次性的)⽤它,不需要其他地⽅调⽤它
  • 一般情况下,编译器可以自动推断出lambda表达式的返回类型,所以我们可以不指定返回类型。但是如果函数体内有多个return语句时,编译器无法自动推断出返回类型,此时必须指定返回类型。
  • 语法:[ 捕获列表 ] (参数列表) -> 返回类型 { 函数体 }
int main(){auto Add = [](int a, int b)->{ return a+b; };cout << Add(1, 2) << endl;return 0;
}

值捕获

void func() {     // c=10 d=20 add(1,2)=23int c = 10;int d = 20;auto add = [c, d](int a, int b) {cout << "c=" << c << endl;cout << "d=" << d << endl;return d+a+b;};d = 50;cout << "add(1, 2)=" << add(1, 2) << endl;
}

引用捕获

void func() {    // c=1 d=50 add(1,2)=53int c = 10;int d = 20;auto add = [&c, &d](int a, int b) {c = a;cout << "c=" << c << endl;cout << "d=" << d << endl;return d+a+b;};d = 50;cout << "add(1, 2)=" << add(1, 2) << endl;
}

隐式捕获、空捕获

void func() {int c = 10;int d = 20;// 如果[&]代表引用捕获,[=]代表值捕获,如果[]为空捕获表示Lambda不能使用所在函数中的变量auto add = [&](int a, int b) {  c = a; cout << "c=" << c << endl;cout << "d=" << d << endl;return d+a+b;};d = 50;cout << "add(1, 2)=" << add(1, 2) << endl;
}

表达式捕获

// c++14之后支持捕获右值,允许捕获的成员用任意的表达式进行初始化,被声明的捕获变量类型会根据 表达式进行判断,判断方式与使用 auto 本质上是相同的
void func4() {auto p = make_unqiue<int>(1);auto add = [v1=1, v2=move(p)](int x, int y)->int{ return x+y+v1+(*v2); };cout << "add(1, 2)=" << add(1, 2) << endl;
}

泛型捕获

void func() {auto add = [](auto x, auto y){ return x+y; };cout << "add(1, 2)=" << add(1, 2) << endl;cout << "add(1.1, 2.2)=" << add(1.1, 2.2) << endl;
}

可变

// 采用值捕获的方式,lambda不能修改其值,如果想要修改,使用mutable修饰;或者采用引用捕获的方式
void func() {int v = 5;auto ff = [v]() mutable { return ++v; };v = 0;auto j = ff(); // ff捕获的是值,即为5,因此j为6int m = 5;auto gg = [&m] {return ++m; };m = 0;auto n = gg(); // gg捕获的是引用,即为0,因此n为1
}

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

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

相关文章

【科技素养题】少儿编程 蓝桥杯青少组科技素养题 信息素养真题及解析第26套

少儿编程 科技素养 信息素养真题第26套 1、本次考试名称STEMA是STEM Assessment 的缩写。在保持第一个和最后一个字母不变的情况下,将 STEMA 的字母排列组合&#xff0c;一共可以组成&#xff08;&#xff09;个与原先不同的组合。 A、5 B、6 C、12 D、20 答案&#xff1a…

基础算法-去重字符串,辗转相除法,非递归前序遍历二叉树题型分析

目录 不同子串 辗转相除法-求最大公约数 二叉树非递归前序遍历 不同子串 从a开始&#xff0c;截取 a aa aaa aaab 从第二个下标开始a aa aab 从第三个 a ab 从第四个 b 使用set的唯一性&#xff0c;然后暴力遍历来去去重&#xff0c;从第一个下标开始截取aaab a aa aaa aaab…

激光是如何产生的?

激光产生的原理 美国于1960年成功研制出世界上第一台红宝石激光器&#xff0c;我国也于1961年成功研制出第一台国产红宝石激光器&#xff08;诞生于中国科学院长春光学精密机械研究所&#xff09;&#xff0c;激光技术被认为是第二个20世纪&#xff0c;继量子物理、无线电技术、…

实时数仓之实时数仓架构(Hudi)

目前比较流行的实时数仓架构有两类&#xff0c;其中一类是以FlinkDoris为核心的实时数仓架构方案&#xff1b;另一类是以湖仓一体架构为核心的实时数仓架构方案。本文针对FlinkHudi湖仓一体架构进行介绍&#xff0c;这套架构的特点是可以基于一套数据完全实现Lambda架构。实时数…

element-ui 自定义点击图标/文本/按钮触发el-date-picker时间组件,不使用插槽

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1. 图片预览 2.上代码 2.1html <el-button class"hide_input" size"small"><svg t"1711608996149" class"icon" viewBox"0 0 1024 1024" version"1.1"…

Linux第85步_EXTI外部中断

1、在stm32mp157d-atk.dts文件中添加“led0”和“key0”节点 打开虚拟机上“VSCode”&#xff0c;点击“文件”&#xff0c;点击“打开文件夹”&#xff0c;点击“zgq”&#xff0c;点击“linux”&#xff0c;点击“atk-mp1”&#xff0c;点击“linux”&#xff0c;点击“my_l…

【opencv】教程代码 —ShapeDescriptors

检测和显示图像的轮廓 在图像中搜索并显示轮廓边缘多边形、轮廓矩形和包围圆 获取包含检测到的轮廓的椭圆和旋转的矩形 图像轮廓检测和轮廓凸包 计算图像中的轮廓的矩&#xff08;包括面积、重心等&#xff09;并进行显示 创建和绘制一个多边形图像然后计算并显示图像上每个点到…

[RoarCTF 2019]Online Proxy --不会编程的崽

这几天也是ctf做得有点头疼了。好些序列化的题没碰&#xff0c;一直做些sql注入类的题目。闲来无事&#xff0c;在更一次sql注入吧。 整个页面就这点信息。首先想想为什么他能获取你的ip。猜测是数据包X-Forwarded-For。 它还输出上次访问页面客户端的ip。很明显了&#xff0c…

誉天华为认证云计算课程如何

HCIA-Cloud Computing 5.0 课程介绍&#xff1a;掌握华为企业级虚拟化、桌面云部署&#xff0c;具备企业一线部署实施及运维能力 掌握虚拟化技术、网络基础、存储基础等内容&#xff0c;拥有项目实施综合能力 满足企业虚拟化方案转型需求&#xff0c;应对企业日益多样的业务诉求…

基于SpringBoot的“招生管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“招生管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 系统首页界面图 学生注册界面图 …

基于Java的新生入学报到管理系统的设计与实现(论文+源码+PPT)_kaic

摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&#xff0c;使信息…

多源统一视频融合可视指挥调度平台VMS/smarteye系统概述

系统功能 1. 集成了视频监控典型的常用功能&#xff0c;包括录像&#xff08;本地录像、云端录像&#xff08;录像计划、下载计划-无线导出&#xff09;、远程检索回放&#xff09;、实时预览&#xff08;PTZ云台操控、轮播、多屏操控等&#xff09;、地图-轨迹回放、语音对讲…