C++11·部分重要语法

目录

列表初始化({ }初始化)

1.对于自定义类型来说

2.使用{ }初始化时,可以省略赋值符号=。

3.C++11内置类型也支持{ }初始化。

4.单参数类型转换可以不用{ }直接等号赋值,也是列表初始化。

​编辑

5.initialize_list

右值引用与移动语义

左值引用or右值引用

左值

右值

相互引用关系

引用延长生命周期

参数匹配

移动构造和移动赋值

右值引用和移动语义在传参中的提效

lambda表达式(匿名函数对象)

捕捉列表

捕捉方式

mutable

小知识


列表初始化({ }初始化)

C++11以前,只有数组和结构体(没有用户定义的构造函数、没有私有或保护的非静态数据成员、没有基类、没有虚函数的)支持{ }初始化;C++11之后,几乎一切对象都可使用{ }初始化。

使用一个日期类来演示

1.对于自定义类型来说

本质是类型转换,中间产生临时对象,不过优化后是直接构造。

将2025,3,27按照Date类的构造函数来产生临时对象,然后赋给d1对象,优化后就成了直接调用Date类的构造函数构造d1对象。

2.使用{ }初始化时,可以省略赋值符号=。

3.C++11内置类型也支持{ }初始化。

4.单参数类型转换可以不用{ }直接等号赋值,也是列表初始化。

5.initialize_list

上面的初始化很方便,但对于对象容器的初始化还不太方便,比如一个vector对象,想用N个不同值构造初始化,就要去实现对应的构造函数。

C++11中实现了一个std::initialize_list的类,这个类的本质是开一个数组,将数据拷贝到数组中,然后进行对象的构造,支持迭代器遍历,但数据的类型要相同。

it 和 itt 会指向同一块临时数组空间。

在语法识别时,如果没有匹配的构造函数,就不能进行隐式类型转换,就会按照initialize_list处理

右值引用与移动语义

左值引用or右值引用

左值

可以获取地址的,可出现在赋值符号=的左边或者右边的一个表示数据的表达式(如变量名、解引用的指针等)。

对左值的引用就是左值引用。

右值

不可以获取地址的,不可以修改的,只能出现在赋值符号=的右边的表示数据的表达式(如匿名对象、表达式结果产生的临时对象、函数返回的临时对象、字符常量等)

对右值的引用就是右值引用。

核心区别就是能否取地址。底层都是指针

相互引用关系

1.左值引用不能直接引用右值,但const左值可以引用右值。

2.右值引用不能直接引用左值,但右值引用可以引用move左值(move是进行类型强转的一个函数)。

3.右值引用后值就可以修改了,因为右值引用算一个变量表达式,变量表达式是左值,可以修改。

引用延长生命周期

临时对象和匿名对象生命周期只在当前行,引用可以延长到与引用生命周期相同(右值引用或const左值引用)。

参数匹配

函数传参时,实参为左值会匹配左值引用,const左值匹配const左值引用,右值匹配右值引用。

 

移动构造和移动赋值

移动构造函数是一种构造函数,类似拷贝构造函数,不过要求第一个参数是该类类型的右值引用,而且如果有额外参数,额外参数必须有缺省值。

移动赋值是一个赋值运算符的重载,和拷贝赋值构成重载,类似拷贝赋值函数,不过要求第一个参数是该类类型的右值引用。

 

移动构造和移动赋值的本质是移动资源,是“抢走”引用的右值对象的资源来提高效率,而不是像拷贝构造和拷贝赋值那样拷贝资源,对于包含深拷贝的成员变量的类才有意义。

右值引用和移动语义在传参中的提效

如果实参是一个左值,容器内部继续调用拷贝构造进行拷贝。

如果实参是一个右值,容器内部则调用移动构造,直接将右值对象的资源转移到容器空间的对象上,因为实参为右值时,一般都是生命周期要结束的变量或者常量,所以直接将其资源转移是没有问题的。

lambda表达式(匿名函数对象)

特点

1. 和普通函数不同的是它是可以定义在函数内部的“函数”。

2.lambda表达式语法对于使用层而言没有类型,所以我们一般用auto或者模版参数定义的对象去接收lambda对象。

3.lambda表达式格式:[capture - list] (parameters) -> return type {function boby}

[capture - list]:捕捉列表,要出现在lambda表达式的开始位置,编译器根据[ ]来判断接下来的代码是否为lambda函数,捕捉列表能捕捉上下文中的变量供lambda函数使用,可以传值和传引用捕捉,如果捕捉列表为空,也不可以省略。

(parameters) :参数列表,与普通函数的参数列表相似,如果参数列表为空,可以全部省略。

-> return type :返回值类型,用追踪返回类型的形式来声明函数返回值类型,没有返回值可全部省略。不过一般返回值类型明确,也可省略,让编译器自动推导。

{function boby}:函数体,和普通函数类似,可以使用参数和捕捉到的变量,不可省略。

极简版:  

正常版:

实用场景

例:当需要在不同位置比较两个对象的不同数据来实现排序等操作时。

一个学生类的vector数组,如果又需要按身高排升序、降序,又需要按体重排升序、降序,仿函数实现不太好弄,但只需要写一个lambda表达式即可。

捕捉列表

lambda表达式中默认只能使用lambda函数体和参数中的变量,想使用外层作用域中的变量就需要进行捕捉。

注:1.局部的静态变量和全局变量是不需要捕捉就可以使用的,也不能捕捉。

2.捕捉的变量默认为const,传值捕捉的变量不可修改,传引用捕捉的变量可以修改,但修改会影响到外层作用域中的变量值。

捕捉方式

1.显示传值和传引用捕捉

[a,b,&c]      &c为引用,不是取地址。

2.隐式值/引用捕捉

[=]     隐式值捕捉(不可修改):在lambda表达式中用了哪些变量,就在外层作用域中捕捉哪些变量。

[&]     隐式引用捕捉(可修改):在lambda表达式中用了哪些变量,就在外层作用域中捕捉哪些变量。

3.混合捕捉

[&,a,b]      a、b为传值捕捉,其余全为引用捕捉

[=,&a,&b]  a、b为传引用捕捉,其余全为值捕捉

注:&和= 符号只能放在开头。

mutable

传值捕捉相当于用const修饰拷贝来的值,mutable可以去掉const属性,让其可以修改,但修改不会影响外部作用域中的值,因为是拷贝。

小知识

1.\ddd d为数字,表示1到3个八进制的数字,   \xdd d为数字,表示两个十六进制的数字。

2.sizeof中的表达式不会计算

例:short a = 4; int b = 3;

cout<<sizeof(a=b+1) <<' ';

cout<<a;

打印结果为2 4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值