10 C++11

10 C++11

  • 1、类型推导
    • 1.1 auto关键字
    • 1.2 auto类型推断本质
  • 2、类型计算
    • 2.1 类型计算分类
    • 2.2 类型计算的四种规则
    • 2.3 返回值类型计算
  • 3、列表初始化
  • 4、Lambda表达式
    • 4.1 前置知识
    • 4.2 Lambda表达式
    • 4.3 捕获表
  • 5、右值引用
    • 5.1 概念
    • 5.2 左值引用和右值引用
  • 6、移动语义

1、类型推导

1.1 auto关键字

  • C++98中,auto表示栈变量,通常省略不写
void foo(void){
	int i;
	auto int j;//表示在栈里分配的
}
  • C++11中,给auto赋予新的语义,表示自动类型推导
    • 既根据对变量进行初始化时所使用的数据的类型,由编译器自动推导出所定义变量的实际类型
auto i=0; -> int j=10;
auto j=i; -> int j=i;

1.2 auto类型推断本质

·按照定义独立对象并根据初始化数据的类型进行推导。
注意:无法自动推断const,只能自己在auto的上下文显示指明。但是有两种情况是除外的:
1:如果给出的初始化数据类型为常量指针,则可以自动推导出const
2:auto与引用的联合联用
- 按照定义独立对象并根据初始化数据的类型进行推导,所以不可能推导出引用
- 除非auto的上下文指明按照引用推导若指明按引用推导并且目标带有常属性,则可以自动推导const

/*类型推导  
linux 默认是c98标准的,如果需要编译的话需要添加 -std=c++11 
类型推导绝对不是类型照抄
*/
int main(){
	int a = 10;
	auto c = a;
	cout << "c的类型" << typeid(c).name() << endl;// typeid无法获取到对象的常属性
	c++;// 允许更改,说明不被const修饰
	cout <<"&c:"<< &c <<"&a:"<< &a << endl;
	
	const int b = 20;
	auto d = b;
	cout << "d的类型" << typeid(d).name() << endl;
	cout << "&d:" << &d<< "&b:" << &b << endl;
	d++;// 允许更改,说明不带const

	const auto e = b;// 自己在auto上添加const
	cout << "e的类型" << typeid(e).name() << endl;
	cout << "&e:" << &e << "&d:" << &d << endl;
	// e++;// 不允许更改,说明带const

	auto f = &b;// 如果初始化数据的类型为常指针,则可以自动推导出const
	cout << "f的类型为:" << typeid(f).name() << endl;
	// *f = 888; // *f不允许更改
	f = NULL; // f是可以更改,说明推导出来的类型是 const int *
	return 0;
}
/*类型推导和引用的联合使用*/
int main(){
	int a = 10;
	const int b = 10;

	auto & d = a;
	cout << "d的类型" << typeid(d).name() << endl; 
	cout << "&d:" << &d << "&a:" << &a << endl; // 地址相同,说明是别名
	d++;

	auto&e = b; // 这里指明了e是引用推导,并且b带有常属性,则可以自动推导出const
	cout << "e的类型" << typeid(e).name() << endl;
	cout << "&e:" << &e << "&b:" << &b << endl;// // 地址相同,说明是别名
	//e++; // 出错,说明不能更改 那么e的类型为const int &
	return 0;
}
  • auto关键字的使用限制
    • 1:函数形参类型无法推导(C++14标准支持)。
    • 2:类的成员变量无法推导。
void foo(auto v){}

2、类型计算

2.1 类型计算分类

c语言:sizeof-计算类型的大小
C++语言:typeid-可以获取类型的信息字符串
C++11:decltype-获取参数表达式的类型
注意事项:类型推导和类型计算都是由编译器确定,并不是运行期确定

/*类型计算*/
int main(){
	const int a = 10;
	auto  b = a; // 类型推导
	cout << "b的类型" << typeid(b).name() << endl; 
	cout << "&b:" << &b << "&a:" << &a << endl; 
	b++;// 允许更改,所以推导出来的类型是int
	decltype(a)c = 100;// 类型计算 初始值可以设置和a不一样
	cout << "c的类型" << typeid(c).name() << endl;
	cout << "&c:" << &c << "&a:" << &a << endl;// // 地址不相同相同
	// c++; // 出错,说明不能更改 那么c的类型为const int 
	return 0;
}
  • 类型推导和类型计算的比较
    1:类型计算比类型推导在类型的确定上更加精准
    2:类型计算比类型推导在初值的确定上更加灵活

2.2 类型计算的四种规则

  • 1:如果给decltype传递的为标识符表达式,decltype取该标识符的类型作为最终计算出的类型
int main(){
	int a = 10;
	// 如果给decltype传递的为标识符表达式,decltype取该标识符的类型作为最终计算出的类型
	decltype(a)b = a;// 类型计算
	cout << "b的类型" << typeid(b).name() << endl;
	cout << "&b:" << &b << "&a:" << &a << endl;// // 地址不相同
	b++; // 能更改说明b的类型为 int 
	return 0;
}
  • 2:如果给decltype传递的为函数表达式,decltype取该函数的返回值类型作为最终计算出的类型
float foo(){
	cout << "函数被调用" << endl;
	return 3.14;
}
int main(){
	int a = 10;
	// 如果给decltype传递的为函数表达式,decltype取该函数的返回值类型作为最终计算出的类型
	decltype(foo())b = a;// 并不会去实际调用foo()函数,类型计算是编译器确定的,不是运行时
	cout << "b的类型" << typeid(b).name() << endl;
	cout << "&b:" << &b << "&a:" << &a << endl;// // 地址不相同
	b++; // 能更改说明b的类型为 float 
	return 0;
}
  • 3:如果给decltype传递的为其他表达式,并且表达式的结果为左值,则取该左值引用的类型作为最终计算出的类型
int main(){
	int a = 10;
	// 如果给decltype传递的为其他表达式,并且表达式的结果为左值,则取该左值引用的类型作为最终计算出的类型
	decltype(++a)b = a;
	cout << "b的类型" << typeid(b).name() << endl;
	cout << "&b:" << &b << "&a:" << &a << endl;// // 地址相同
	b++; //允许更改 说明b的类型为int &
	return 0;
}
  • 4:如果给decltype传递的为其他表达式,并且表达式的结果为右值,则取该右值本身的类型作为最终计算出的类型
int main(){
	int a = 10;
	// 如果给decltype传递的为其他表达式,并且表达式的结果为右值,则取该右值本身的类型作为最终计算出的类型
	decltype(a++)b = a;
	cout << "b的类型" << typeid(b).name() << endl;
	cout << "&b:" << &b << "&a:" << &a << endl;// // 地址不相同
	b++; //允许更改 说明b的类型为int 
	return 0;
}

2.3 返回值类型计算

  • 返回值类型后置
auto foo(int x, double y)->decltype(x+y){// 返回值类型后置,通过decltype计算得出
	return  x + y;
}
int main(){
	auto f = foo(1, 3.1);// 类型推导
	cout << typeid(f).name() << endl; // double类型
	return 0;
}

3、列表初始化

基本类型,类类型,结构/联合/枚举类型等等的单个对象或对象数组,都可以采用形式完全统一的列表初始化语法
进行对象的初始化

  • 书写形式:类型 对象 {初值表};
    -int a{123);
    -new double {1.23);
    -string c{“123”};
    -struct Student {d,“张飞”,20,{1997,10,10}};
    -float e[]{1.1,2.2,3.3};
struct BD{
	int m_year;
	int m_month;
	int m_day;
};
struct myStudent{
	string m_name;
	int m_age;
	BD m_body;
};
class Human{
public:
	Human(int age = 0, const char* name = "无名") :m_age(age), m_name(name){

	}
	int m_age;
	string m_name;
};
int main(){
	int a = { 123 }; // int a=123
	cout << "a=" << a << endl;

	double* pa = new double{ 3.14 };// double *pa = new double(3.14);
	double *pb{ new double{ 3.14 } };
	cout << "*pa=" << *pa << " *pb=" << *pb << endl;

	int b[]{1, 2, 3};//int b[] = { 1, 2, 3 };
	for (int i = 0; i < 3; i++){ cout << b[i] << ' '; }
	int *parr{ new int[3]{4, 5, 6} };
	for (int i = 0; i < 3; i++){ cout << parr[i] << ' '; }
	delete[]parr;
	myStudent s{ "zs", 22, { 1997, 5, 7 } }; // myStudent s = { "zs", 22, { 1997, 5, 7 } };
	cout << s.m_name << s.m_age << s.m_body.m_year << s.m_body.m_month << s.m_body.m_day << endl;

	Human h{ 20, "赵云" };//Human h (20, "赵云" )
	cout << h.m_age << h.m_name << endl;
	return 0;
}
  • 小括号操作符函数
class AA{
public:
	int operator()(int x, int y){
		return x + y;
	}
};
int main(){
	AA a;
	cout << a(100, 200) << endl;;// a.operator()(100,200)
}

4、Lambda表达式

4.1 前置知识

在C++中函数的作用域中可以有类型,也可以有表达式

  • 针对于函数内部定义了类型,编译器先编译函数内部的类型,然后在编译函数体本身的代码
int a;
void foo(int b){
	int c;
	class A{
	public:
		void bar(int d){
			a = 0;// 能访问
			// b = 0; // 不能访问
			// c = 0; // 不能访问
			d = 0;// 能访问
		}
	};
}

4.2 Lambda表达式

  • 语法规则:
[捕获表](参数表)选项->返回类型
{
	函数体
}
  • 使用
int main(void){
	int a = 10, b = 20;
	auto c =[](int x, int y)->int{return x > y ? x : y; };
	// 编译器 (1) 生成一个类  (2) 类内定义一个小括号操作符函数 (3) 返回这个类的匿名对象
	cout<<c(a,b)<<endl;
	return 0;
}
  • 本质
    lambda表达式本质其实是一个类并且最终返回值为这个类的对象,因此对lambda表达式的调用就是该对象的函数操作符的调用
    在这里插入图片描述

解释:编译器在编译到Lambda表达式时,编译器会生成一个类Z4XXX的类,类中定义一个小括号操作函数,函数体里面填充Lambda的函数体内容,函数的返回值类型为Lambda中定义的返回类型。
其中

  • 可以没有返回值类型,将根据return推断
int main(void){
	int a = 10, b = 20;
	auto c = [](int x, int y){return x + y; };// 当没有返回值类型时,中间的箭头可以省略
	cout << c(a, b) << endl;
	return 0;
}
  • 如果连return也没有,则返回值为void
int main(void){
	int a = 10, b = 20;
	[](int x, int y){cout<< x + y<<endl; }(a,b);// 如果连return也没有,则返回值为void
	return 0;
}
  • 参数为void可以省略不写的
int main(void){
	int a = 10, b = 20;
	[]{cout << "12345" << endl; }();// 如果没有形参,返回值类型也为void那么小括号和中间的剪头都可以省略
	return 0;
}

4.3 捕获表

  • []-不捕获任何外部变量
  • [variable]-捕获外部变量的值
  • [&variable]-按引用捕获,外部变量的别名
  • [this]-捕获this指针,访问外部对象的成员
int a = 10;
class Y{
public:
	Y(int m_e) :e(m_e){};
	void foo(int c = 30){
		cout << "---" << endl;
		// []-不捕获外部变量的值
		[](int d = 40){
			cout << "a=" << a << endl;
			cout << "b=" << b << endl;
			// cout << "c=" << c << endl; // 错误
			cout << "d=" << d << endl;
			// cout << "e=" << e << endl; // 错误
		}();
		cout << "--------------[c]--------" << endl;
		// [variable]-捕获外部变量只读
		[c](int d = 0){cout << "c=" << c << endl; }();
		cout << "--------[&c]---------" << endl;
		// [&variable]-按引用捕获,外部变量的别名
		[&c]{c++; cout << "c=" << c << endl; }();
		cout << c << endl;
		// [this]-捕获this指针,访问外部对象的成员
		cout << "--------[this]---------" << endl;
		[this]{cout << "e=" << e << endl; }();
	}
private:
	static int b;
	int e;
};
int Y::b = 10;

int main(){
	Y y(4);
	y.foo();
	return 0;
}
  • [=]-按值捕获所有的外部变量,也包括this
  • [&]-按引用捕获所有的外部变量,也包括his
  • [=,&variable]-按值捕获所有的外部变量包括this,但是指定的外部变量按引用捕获。
  • [&,=variable]-按引用捕获所有的外部变量,也包括this,但是指定的外部变量按值捕获。

5、右值引用

5.1 概念

左值引用是别名,右值引用就是真名
左值:可以“取”地址的值就是左值,左值通常具名
右值:不可“取”地址的值就是右值,右值通常匿名
左值细分为非常左值和常左值
- 非常左值:有名字、可以取地址、没有常属性
- 常左值:有名字、可以取地址、有常属性
右值细分为纯右值和将亡值
- 纯右值:有一块无名内存,里面存放了基本类型的数据
- 将亡值:有一块无名内存,里面存放了类类型的数据

5.2 左值引用和右值引用

  • 左值引用只能引用左值,不能引用右值
  • 右值引用只能引用右值,不能引用左值
  • 常左值引用,既能引用左值,也能引用右值
  • 常右值引用,完全可以被常左值引用替代
/*左值引用和右值引用的差别*/
int main(){
	// 左值引用只能引用左值,不能引用右值
	int a=1, c=2;
	int & ra = a;
	// int & rb = a + c; // 错误 左值引用不能引用右值
	int &&rb = a + c;// 使用右值引用
	// int &&rc = a;// 错误 右值引用只能引用右值,不能引用左值
	cout << rb << endl;
	const int & _l = a; // 引用左值
	const int & _r = a + c; // 引用右值
	// 常左值引用会丧失修改目标的权限
	// _l = 9;// 错误
	// 右值引用不会丧失修改目标的权限
	rb = 90;
	cout << rb << endl;
}

6、移动语义

  • 方法:
    资源的转移 代替 资源的重建
  • 作用:
    保证功能正确的情况下,做到性能提升
//深拷贝构造函数 资源的重建
 String(const String & that) :m_psz(new char[strlen(that.m_psz) + 1]){
    cout << "深拷贝构造 资源的重建" << endl;
    strcpy(m_psz, that.m_psz); // 没有复制地址,复制了数据(深拷贝)
}
// 深拷贝构造函数 资源的转移 
String(String && that):m_psz(that.m_psz){
	that.m_psz = NULL;
	cout << "资源转移" << endl;
}
// 深拷贝赋值函数 资源的重建
 String& operator=(/*String* this*/const String & that){
	cout<<"深拷贝赋值函数 资源的重建"<<endl;
	if (this == &that){}// 防止出现用户自己给自己赋值
	else{
		delete[] this->m_psz;// 编译器会先定义一个m_psz,并初始>化为空串,所以需要先释放内存
		this->m_psz = new char[strlen(that.m_psz) + 1];// 申请新资源
		strcpy(m_psz, that.m_psz); // 拷贝新内容
	}
	return *this;// 返回自引用
}

// 拷贝赋值函数 资源的转移
String& operator=(String&& that){
	cout<<"拷贝赋值函数 资源的转移"<<endl;
	delete this->m_psz;
	this->m_psz=that.m_psz;
	that.m_psz=NULL;
	return *this;
}
//在linux下 命令行输入:g++ abc.cpp -std=c++11 -fno-elide-constructors
int main(){ 
	String s1=String("hello"); // 深拷贝构造函数 资源的转移
	String s2=s1;// 拷贝构造函数 资源的重建
	s2=s1;// 拷贝赋值函数 资源的重建
	s2=String("hello");// 拷贝赋值函数 资源的转移
}

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

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

相关文章

el-tree回显复选框时半选中和全选中的树

项目需求如下&#xff1a;当我点击“编辑”后&#xff0c;需要在tree树上全勾中和半勾中选项&#xff0c;由于后端接口返回的tree树是含了父级节点id的数组集合&#xff0c;所以我们回显时需要处理好这个全勾中和半勾中的问题。 主要思路如下&#xff0c;我们通过setData方法获…

【Java】已解决:java.lang.OutOfMemoryError: Java heap space

文章目录 一、问题分析背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决Java&#xff1a;java.lang.OutOfMemoryError: Java heap space 一、问题分析背景 在Java开发过程中&#xff0c;有时我们会遇到java.lang.OutOfMemoryError: Java heap spa…

在typora中利用正则表达式,批量处理图片

一&#xff0c;png格式 在 Typora 中批量将 HTML 图片标签转换为简化的 Markdown 图片链接&#xff0c;且忽略 alt 和 style 属性&#xff0c;可以按照以下步骤操作&#xff1a; 打开 Typora 并加载你的文档。按下 Ctrl H&#xff08;在 Windows/Linux 上&#xff09;或 Cmd…

【Python】理解『下采样』:原理与应用

是你多么温馨的目光 教我坚毅望着前路 叮嘱我跌倒不应放弃 没法解释怎可报尽亲恩 爱意宽大是无限 请准我说声真的爱你 &#x1f3b5; Beyond《真的爱你》 在数字信号处理、图像处理和机器学习中&#xff0c;下采样&#xff08;Downsampling&#xff09;是…

【Java04】引用变量数组初始化的内存机制

引用类型数组指向的元素也是引用。其本质是&#xff1a; 由一个在栈上的引用数组变量指向一块堆内存&#xff1b;这块堆内存里存储的元素是引用&#xff0c;又分别指向其他堆内存。 class Person // Person是一个自定义的类 {public int age;puiblic double height;public vo…

Java课程设计:基于Javaweb的校园订餐系统

文章目录 一、项目介绍二、项目技术栈三、核心代码四、项目展示五、源码获取 一、项目介绍 在当今互联网高速发展的时代,大学校园内的学生生活正在发生着翻天覆地的变化。其中,校园内的餐饮服务无疑是亟需改革和创新的领域之一。 传统的校园食堂模式,往往存在就餐高峰时段拥挤…

使用了代理IP怎么还会被封?代理IP到底有没有效果

代理IP作为一种网络工具&#xff0c;被广泛应用于各种场景&#xff0c;例如网络爬虫、海外购物、规避地区限制等。然而&#xff0c;很多用户在使用代理IP的过程中却发现自己的账号被封禁&#xff0c;这让他们不禁产生疑问&#xff1a;使用了代理IP怎么还会被封&#xff1f;代理…

Web前端项目-交互式3D魔方【附源码】

交互式3D魔方 ​ 3D魔方游戏是一款基于网页技术的三维魔方游戏。它利用HTML、CSS和JavaScript前端技术来实现3D效果&#xff0c;并在网页上呈现出逼真的魔方操作体验。 运行效果&#xff1a; 一&#xff1a;index.html <!DOCTYPE html> <html><head><…

刚入职,写接口用了PUT和DELETE方法,结果被同事喷了,感觉自己被针对了

事情是这样&#xff0c;某社交平台上有个兄弟发帖&#xff0c;说自己刚入职国企&#xff0c;写了个借口&#xff0c;用了PUT和DELETE方法&#xff0c;前段说不能用这两个&#xff0c;这位仁兄感觉很委屈&#xff0c;特地发帖吐槽。 其实站在安全的角度来说&#xff0c;真没冤枉…

爱了爱了,11款超良心App推荐!

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/今天&#xff0c;我们向你推荐十款与众不同但又不错的win10软件&#xff0c;它们都有各自的功能和优点&#xff0c;相信你一定会喜欢。 1.图片处…

第 4 章:从 Spring Framework 到 Spring Boot

通过前面几个章节的介绍&#xff0c;相信大家已经对 Spring Framework 有了一个基本的认识&#xff0c;相比早期那些没有 Spring Framework 加持的项目而言&#xff0c;它让生产力产生了质的飞跃。但人们的追求是无止境的&#xff0c;这也驱动着技术的发展。开发者认为 Spring …

【计算机组成原理】指令系统考研真题详解之拓展操作码!

计算机组成原理&#xff1a;指令系统概述与深入解析 1. 指令系统概述 计算机软硬件界面的概念 在计算机组成原理中&#xff0c;指令系统扮演着至关重要的角色&#xff0c;它是计算机软硬件界面的核心。软件通过指令与硬件进行通信&#xff0c;硬件根据指令执行相应的操作。指…

基于STM32和人工智能的智能气象站系统

目录 引言环境准备智能气象站系统基础代码实现&#xff1a;实现智能气象站系统 4.1 数据采集模块4.2 数据处理与分析4.3 控制系统4.4 用户界面与数据可视化应用场景&#xff1a;智能气象管理与优化问题解决方案与优化收尾与总结 1. 引言 随着气象科技的进步&#xff0c;智能…

定个小目标之刷LeetCode热题(21)

这是道技巧题&#xff0c;利用了 &#xff08;num - 1&#xff09;% n 计算下标的形式来将数组元素与数组索引产生映射关系&#xff0c;代码如下&#xff0c;可以看下注释 class Solution {public List<Integer> findDisappearedNumbers(int[] nums) {int n nums.lengt…

Qt画五角星,简单图表

五角星&#xff1a; 代码&#xff1a; widget.cpp #include "widget.h" #include "ui_widget.h" #include <QPaintEvent> #include <QPainter> #include <QPainterPath> Widget::Widget(QWidget *parent): QWidget(parent), ui(new U…

广东启动“粤企质量提升工作会议” 着力提升产品和服务质量

6月5日,由广东质量峰会组委会牵头,联合相关质量、信用、打假和检验检测等部门共同举办的“粤企质量提升工作会议”在广州正式启动。本次工作会议旨在贯彻落实《质量强国建设纲要》及《广东省质量强省建设纲要》精神,深入开展全民质量行动,弘扬企业家和工匠精神,营造政府重视质量…

互联网应用主流框架整合之SpringMVC基础组件开发

多种传参方式 在前一篇文章互联网应用主流框架整合之SpringMVC初始化及各组件工作原理中讨论了最简单的参数传递&#xff0c;而实际情况要复杂的多&#xff0c;比如REST风格&#xff0c;它往往会将参数写入请求路径中&#xff0c;而不是以HTTP请求参数传递&#xff1b;比如查询…

acwing 5575. 改变数值 | c++题解及解释

acwing 5575. 改变数值 题目 代码及解释 #include <iostream> #include <cstring> #include <algorithm> #include <unordered_map> using namespace std;const int N305; int a[N],b[N]; unordered_map<int,int>f[N]; const int INF1e9;int gc…

异或运算的原理以及应用

异或&#xff08;XOR&#xff09;是计算机科学和数字电路中常用的运算之一。异或运算符通常用符号“⊕”或“^”表示&#xff0c;它有着简单而独特的性质&#xff0c;使其在数据加密、错误检测与纠正等多个领域得到了广泛的应用。在网络上我们传输的每一比特数据都经过了异或运…

如何用 ChatGPT DALL-E3绘画(10个案例)

如何用ChatGPT绘画——10个案例&#xff08;附提示词&#xff09; DALL•E 3可以在ChatGPT plus里直接使用了。 如果想免费使用&#xff0c;可以用新必应免费使用。 上次有个朋友问&#xff1a;DALL•E 3 有什么用。 这里用十个案例&#xff0c;来解释一下这个问题。 1.创…