c++11详解

目录

1.列表初始化

2.声明

3.右值引用和移动语句

4. c++11新的类功能

5. 可变参数模板

 6.lambda表达式

7.包装器

8. 后言


1. 列表初始化

1.1 {}的初始化

(1) c++98标准规定可以使用{}对数组以及结构体进行统一的列表初始化.

struct Point
{
	int _x;
	int _y;
};

int main()
{
	int a1[] = { 1, 2, 3, 4, 5 };
	int a2[5] = { 0 };
	Point p = { 1, 2 };
	return 0;
}

(2) c++11里面增加了对{}的使用范围, 可以对所以的内置类型自定义类型的类型使用初始化列表, 可以加=;也可以不加.

struct Point
{
	int _x;
	int _y;
};

int main()
{
	int x1 = 1;
	int x2{ 2 };
	int a1[]{ 1, 2, 3, 4, 5 };
	int a2[5]{ 0 };
	Point p{ 1, 2 };
	return 0;
}

(3) 创建对象也可以使用列表初始化的方式调用构造函数初始化.

class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		, _month(month)
		,_day(day)
	{
		cout << "Date(int year, int month, int day)" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2022, 1, 1);

	Date d2{ 2022, 1, 2 };
	Date d3 = { 2022, 1, 2 };
	return 0;
}

 1.2 initializer_list

 (1)initializer_list的类型:

(2)initializer_list的使用场景:

一般作为构造函数的参数; 方便初始化对象,  也可以是operator=的参数, 那么就可以用{}进行赋值.

c++11里面对STL的构造函数都添加了initializer_list; 就是允许{}进行对象的初始化的一种方法.支持范围for.


//int main()
//{
//	auto il = { 10, 20 ,30 };
//	cout << typeid(il).name() << endl;
//	return 0;
//}

//int main()
//{
//	vector<int> v{ 1, 2, 3, 4 };
//	list<int> lt{ 1, 2 };
//	map<string, string> sict = { {"sort", "排序"}, {"inset", "插入"} };
//
//	v = { 1, 2, 3 };
//	return 0;
//}

int main()
{
	//多参数构造类型转换: 构造+拷贝构造-> 直接构造.
	Date d2 = { 2023, 11, 25 };
	auto il1 = { 10, 20, 30, 40, 50 };

	initializer_list<int> il2 = { 11, 22, 33 };

	initializer_list<int>::iterator it2 = il2.begin();
	//while (it2 != il2.end())
	//{
	//	cout << *it2 << endl;
	//	it2++;
	//}
	//cout << endl;

	for (auto e : il2)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

2.  声明

2.1 auto

c++98里面定义auto是一种类型局部自动存储类型, but在局部域中定义的变量就是默认是局部自动存储类型, 然而在c++11里面就是自动推断类型, 必须进行显示初始化, 以便于编译器将类型设置为初始化的类型.

 2.2 decltype

 思考一个小问题: 如果我要使用一个我不知道的类型, 怎么做? 

        使用auto吗? 那肯定是不行的, auto在初始化的时候必须给定类型才可以让编译器去推断.那么就要用到decltype. 所以decltype的作用就是将变量的类型声明为表达式指定的类型.

int main()
{
	int i = 1;
	double d = 2.2;

	/*cout << typeid(i).name() << endl;
	cout << typeid(d).name() << endl;*/

	auto j = i;
	auto ret = i * d;
	decltype(ret) x;

	vector<decltype(ret)> v;
	v.push_back(1);
	v.push_back(1.1);

	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

2.3 nullptr

c++里面定义NULL为字面常量0;  但是这个字面常量0既可以表示指针常量, 还可以表示整形常量.所以c++11里面添加nullptr表示为空指针.

 2.4 STL的一些变化

(1) array:

        这个接口其实是对应vector, 其实也没啥用处.

(2) forward_list:

      用来任意位置进行删除和插入操作.

(3) unordered_map

(4) unordered_set

上面两个序列式容器之前在哈希和红黑树里面都有出现, 这里不过多介绍了.

3. 右值引用和移动语句

3.1 左值和右值

 左值:

        一般是变量值或者是解引用的指针; 一般是在赋值符号的左边, 但是右值一定不会出现在赋值符号的左边. 可以获取到地址并且可以对它进行赋值, 如果是const就不行咧.

左值引用:

        对左值进行引用, 给左值取别名.

int main()
{
	//左值
	int* p = new int(0);
	int  b = 1;
	const int c = 2;

	//左值引用:
	int*& rp = p;
	int& rb = b;
	const int& rc = c;
	int& pvalue = *p;
	return 0;
}

右值:

        通常是字面常量, 表达式返回值, 函数返回值(不能是左值引用的返回值), 右值可以出现在赋值符号的右边, 但是不能获取到地址. 还有就是右值无法在赋值符号的左边; 因为左边必须是左值, 右值有常属性所以不行!

右值引用:

        对右值的引用, 对右值取别名.

注意:

        右值是无法取到地址的, 但是取别名之后, 被存储到特定的位置, 并且可以拿到那个位置的地址.

int main()
{
	double x = 1.1, y = 2.2;

	10;
	x + y;
	fmin(x, y);

	int&& rr1 = 10;
	int&& rr2 = x + y;
	int&& rr3 = fmin(x, y);
	return 0;
}

3.2左值引用和右值引用的区别

左值引用:

        (1) 左值引用只能用于引用左值, 不能用来引用右值;

        (2) but const修饰的左值引用可以引用左值和右值.

右值引用:

        (1) 右值引用只能引用右值, 不能引用左值;

        (2)but move修饰过的左值可以被右值引用使用.

int main()
{
	//左值引用
	int a = 10;
	int& ra1 = a;

	const int& ra2 = 10;
	const int& ra2 = a;
	
	//右值引用
	int&& aa1 = 10;
	int a = 10;
	int&& aa2 = move(a);

	return 0;
}

3.3 右值引用的使用场景

       (1) 先看看左值引用的应用场景, 那就是作为参数或者返回值, 但是如果出了作用域还在那么就可以使用左值引用. 因为左值引用是局部变量, 出了作用域之后不在那怎么把数据传回来捏?

        (2) 右值引用和移动语义的本质: 就是将参数的右值资源直接夺取过来, 然后就不用进行深拷贝了, 这就是移动构造. 进一步提高效率.

        (3) 编译器在调用构造的时候, 有移动构造就调用移动构造, 没有就调用拷贝构造.

        (4) 移动赋值:  重载operator=的时候使用右值引用.

 3.4 右值引用左值的场景分析

右值引用左值不能直接引用, 需要加move进行将左值转化为右值才可以, 但是左值的本质属性还是左值, 并没有改变.  如果是作为拷贝构造函数的参数, 那么就一定要注意, 如果拷贝赋值move之后, 就会将原来的数据交给新的对象, 原来的对象就被置空了.

注意:右值被右值引用之后属性变成了左值.

void push_back (value_type&& val);
int main()
{
 list<bit::string> lt;
 bit::string s1("1111");

 // 这里调用的是拷贝构造
 lt.push_back(s1);

 // 下面调用都是移动构造
 lt.push_back("2222");
 lt.push_back(std::move(s1));
 return 0;
}

3.5 完美转发

使用到模板以及右值引用. 模板里面的&&是表示万能引用, 既可以接受左值, 又可以接收右值,

可以看看下面的代码:

为啥都变成左值啦?  因为右值被右值引用之后属性变成了左值.

如果我们就是想要右值引用怎么办捏? 

        上完美转发, std:: forward. (保持对象原生类型的属性)

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(t);
    //完美转发
    Fun(forward<T>(t));
}

int main()
{
	//右值
	perfectForward(10);
	
	//左值
	int a;
	perfectForward(a);
	perfectForward(move(a));

	//左值
	const int b = 9;
	perfectForward(b);
	perfectForward(move(b));

	return 0;
}
3.5.1 完美转发使用场景
template<class T>
struct ListNode
{
	ListNode* _next = nullptr;
	ListNode* _prev = nullptr;
	T _data;
};
template<class T>
class List
{
	typedef ListNode<T> Node;
public:
	List()
	{
		_head = new Node;
		_head->_next = _head;
		_head->_prev = _head;
	

	void PushBack(T&& x)
	{
		//Insert(_head, x);
		Insert(_head, std::forward<T>(x));
	}

	void PushFront(T&& x)
	{
		//Insert(_head->_next, x);
		Insert(_head->_next, std::forward<T>(x));
	}

	void Insert(Node* pos, T&& x)
	{
		Node* prev = pos->_prev;
		Node* newnode = new Node;
		newnode->_data = std::forward<T>(x); // 关键位置
		// prev newnode pos
		prev->_next = newnode;
		newnode->_prev = prev;
		newnode->_next = pos;
		pos->_prev = newnode;
	}

	void Insert(Node* pos, const T& x)
	{
		Node* prev = pos->_prev;
		Node* newnode = new Node;
		newnode->_data = x; // 关键位置
		// prev newnode pos
		prev->_next = newnode;
		newnode->_prev = prev;
		newnode->_next = pos;
		pos->_prev = newnode;
	}

private:
	Node* _head;
};
int main()
{
	List<string> lt;
	lt.PushBack("1111");
	lt.PushFront("2222");
	return 0;
}

4. c++11新的类功能

c++里面6个默认构造的类分别是: 

        1. 构造函数; 2. 析构函数; 3. 拷贝构造函数; 4. 拷贝赋值重载; 5. 取地址重载; 6. const 取地址重载.

现在又多了移动构造移动赋值,:

注意:

        (1) 如果你没有写移动构造函数, 并且没有写析构函数, 拷贝构造函数, 拷贝赋值重载函数的话, 那么就编译器自动生成移动构造函数.

        (2)如果你没有写赋值重载函数, 并且没有写析构函数, 拷贝构造函数, 拷贝赋值重载函数那么就编译器自动生成移动赋值函数.

        (3)对于内置类型进行浅拷贝, 自定义类型如果实现了移动构造就使用移动构造, 如果没有使用的话就进行深拷贝.

        2.强制生成默认函数的关键字: default 进行显示的移动构造生成.

        3.强制不生成默认函数的关键字: delete

class Person
{
public:
	Person(const char* name = "", int age = 0)
		:_name(name)
		, _age(age)
	{}
	Person(const Person& p)
		:_name(p._name)
		, _age(p._age)
	{}

    //强制生成默认函数
	//Person(Person&& p) = default;
    //强制不生成默认函数
    Person(Person&& p) = delete;

private:
	bit::string _name;
	int _age;
};
int main()
{
	Person s1;
	Person s2 = s1;
	Person s3 = std::move(s1);
	return 0;
}

5. 可变参数模板

// Args 是一个 模板参数包 args 是一个 函数形参参数包
// 声明一个参数包 Args...args ,这个参数包中可以包含 0 到任意个模板参数。
template < class ... Args >
void ShowList ( Args ... args )
{}
注意: 使用参数包是ex到家的, 还有获取参数包得值! 学的想吐血!!!
获取参数值是是用到递归调用的方法.

template <class T>
void PrintArg(T t)
{
	cout << t << " ";
}
//展开函数
template <class ...Args>
void ShowList(Args... args)
{
	int arr[] = { (PrintArg(args), 0)... };
	cout << endl;
}
int main()
{
	ShowList(1);
	ShowList(1, 'A');
	ShowList(1, 'A', std::string("sort"));
	return 0;
}

5.1 比较emplace和insert

emplate的接口是支持万能模板以及可变参数包的. 那和有啥区别捏? 而且emplace接口的优势在哪里捏?

支持了可变参数包, 以及emplace_back是直接构造, push_back是先构造再移动构造.

 6.lambda表达式

引入: lambda底层就是仿函数, 由于当我们定义自定义类型的比较的时候, 都需要写一个类来规定比较的方法(仿函数), 使用起来非常不方便.定义就弄出来lambda表达式.

 6.1lambda表达式的语法:

(1) 格式:[capture-list] (parameters) mutable -> return-type { statement }

capture-list: 捕捉列表, 捕捉上下文的变量

parameters: 参数列表; 和普通函数是一样的.

mutable: 看代码吧, 更加形象.

->returntype: 返回值类型;  和普通函数是一样的.
statement:函数体 和普通函数是一样的.
(2) lambda的类型是 class <lambda_a62159c664704dbd449a2ea762c73c4d>
lambda + uuid;
(3) lambda表达式是一个匿名函数, 如果要使用据需要auto去拿.
int main()
{
	//啥都不做
	[] {};

	//捕捉=上下的变量,返回值类型推到为int.
	int a = 3, b = 4;
	[=] {return a + 3; };

	//没有返回值, 捕捉&的上下文变量, 然后用到函数体里面
	/*auto fun1 = [&](int c) {b = a + c; };
	fun1(10);
	cout << a << " " << b << endl;*/

	/*auto fun2 = [=, &b](int c)->int{return b += a + c; };
	cout << fun2(10) << endl;*/

	int x = 10;
	auto add_x = [x](int a)mutable {x *= 2; return a + x; };
	cout << typeid(add_x).name() << endl;
	cout << add_x(10) << endl;
}

 6.2 捕捉列表

捕捉方式是传值还是传递引用都有区别:

(1) [var]: 传值捕捉

(2) [=]: 传值捕捉, 捕获子作用域里面所有变量(包括this);

(3) [&var]:表示引用传递捕捉变量var

(4) [&]:表示引用传递捕捉所有父作用域中的变量(包括this)
(5) [this]:表示值传递方式捕捉当前的this指针
注意:
(1)捕捉列表有多个参数, 就要用 ' ,' 隔开.
(2)不允许重复传递, 编译器会报错;
(3)lambda表达式之间不能相互赋值;

 6.3 仿函数和lambda表达式:

其实底层来看这两个东西是一样的;  仿函数只是在类里面重载operator()的对象.

 

7. 包装器

7.1 为啥需要包装器, 这是个啥?

(1) function是包装器也是适配器, 本质就是一个类模板.

ret = func(x);

上面这段代码可以是函数返回值, 仿函数, lambda表达式, 那你找到它到底是上面吗?

根本不知道, 而且编译器还会实例化上面出现的所有对象, 那么编译器必定效率低下.

(2) function的头文件#include<functional>

7.2 bind

bind就是一种适配器, 支持可调用对象(函数, 仿函数, lambda表达式), 生成一个新的可调用对象来适应原来的参数列表,  其中的 _n 是一种占位符, 表示可调用对象的位置.

#include <functional>
int Plus(int a, int b)
{
	return a + b;
}

class Sub
{
public:
	int sub(int a, int b)
	{
		return a - b;
	}
};

int main()
{
	//表示绑定函数plus 参数分别由调用 func1 的第一,二个参数指定
	function<int(int, int)> func1 = std::bind(Plus, placeholders::_1, placeholders::_2);

	auto func2 = std::bind(Plus, 1, 2);
	cout << func1(1, 2) << endl;
	cout << func2() << endl;
	 
	Sub s;
	 绑定成员函数
	function<int(int, int)> func3 = std::bind(&Sub::sub, s,	placeholders::_1, placeholders::_2);
	
	
	 参数调换顺序
	//std::function<int(int, int)> func4 = std::bind(&Sub::sub, s,
	//	placeholders::_2, placeholders::_1);
	//cout << func3(1, 2) << endl;
	//cout << func4(1, 2) << endl;

	return 0;
}

8. 后言

其中c++11里面的新增功能, 如果不使用/ 少使用很容易就忘掉, 就比如lambda, 老长的你能在很久不用记得很清楚阿? xdm多用多写! 还有给博主三联, 你绝对学的很好!!!

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

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

相关文章

OpenStack的基本操作

1.实例类型管理 首先用管理员账号登录OpenStack 点击创建实例类型后&#xff1a;可以看见实例类型创建成功 2.项目与租户管理 Openstack有严格的项目及租户管理制度&#xff0c;在项目中使用管理员创建项目&#xff0c;然后为该项目创建一个以你姓名命名的账户为该项目的管理…

N5245B PNA-X 微波网络分析仪

N5245B PNA-X 微波网络分析仪 " 900 Hz/10 MHz 至 50 GHz " N5245B PNA-X 微波网络分析仪&#xff0c;900 Hz/10 MHz 至 50 GHz&#xff0c;2 端口和 4 端口&#xff0c;多达三个信号源。 特点 实现卓越性能 这款 PNA-X 分析仪不仅仅是一款矢量网络分析仪&a…

每日两题 / 46. 全排列 41. 缺失的第一个正数(LeetCode热题100)

46. 全排列 - 力扣&#xff08;LeetCode&#xff09; 经典回溯题&#xff0c;每次搜索选择未选择数字中的一个 当选择了n个数时&#xff0c;将已经选择的数加入答案 class Solution { public:vector<vector<int>> permute(vector<int>& nums) {vector…

进制转换问题

1.十进制转二进制&#xff08;善于使用__int128&#xff09; 3373. 进制转换 - AcWing题库 #include<bits/stdc.h> using namespace std; __int128 x; int x_; string s1; int main(){stack<int> s;while(cin>>s1){int lens1.size();for(int i0;i<len;i)…

短视频素材怎么做?视频素材库那个好?

在这个视频内容占据主导的时代&#xff0c;高质量的无水印视频素材不仅能够丰富视觉体验&#xff0c;还能显著提升你的作品吸引力。为了帮助你在广阔的创意海洋中航行&#xff0c;下面介绍的一系列视频素材网站将为你的项目注入新的活力&#xff0c;让每个创意的火花都能闪耀发…

react之初识state

第二章 - 添加交互 State: 组件的记忆 组件通常需要根据交互更改屏幕上显示的内容。输入表单应该更新输入字段&#xff0c;单击轮播图上的“下一个”应该更改显示的图片&#xff0c;单击“购买”应该将商品放入购物车。组件需要“记住”某些东西&#xff1a;当前输入值、当前…

Multitouch 1.27.28 免激活版 mac电脑多点触控手势增强工具

Multitouch 应用程序可让您将自定义操作绑定到特定的魔术触控板或鼠标手势。例如&#xff0c;三指单击可以执行粘贴。通过执行键盘快捷键、控制浏览器的选项卡、单击鼠标中键等来改进您的工作流程。 Multitouch 1.27.28 免激活版下载 强大的手势引擎 精心打造的触控板和 Magic …

怎么办xgp会员一年多少钱xgp会员怎么开轻松教你xgp会员开通教程

怎么办&#xff1f;xgp会员一年多少钱&#xff1f;xgp会员怎么开&#xff1f;轻松教你xgp会员开通教程 XGP平台是由微软公司开发的xbox游戏平台的pc版本&#xff0c;为电脑玩家提供了一个游玩微软游戏的平台&#xff0c;XGP平台因其独特的会员服务而广受玩家们好评&#xff0…

浓眉大眼的Apple开源OpenELM模型;IDM-VTON试衣抱抱脸免费使用;先进的语音技术,能够轻松克隆任何人的声音

✨ 1: openelm OpenELM是苹果机器学习研究团队发布的高效开源语言模型家族 OpenELM是苹果机器学习研究团队开发的一种高效的语言模型&#xff0c;旨在推动开放研究、确保结果的可信赖性、允许对数据和模型偏见以及潜在风险进行调查。其特色在于采用了一种分层缩放策略&#x…

融合公式调权思考

一般在多目标任务任务中有加法公式、乘法公式、混合加法、非线性公式等&#xff0c;通过业务特性和应用场景选择不同方式&#xff0c;线上调参也有很多方案&#xff0c;自动寻参&#xff08;成本较高&#xff0c;比如进化算法、网格搜索、随机搜索、贝叶斯优化、自动调参工具如…

开发板通过网线连接电脑而上网

简介 关闭win11的防火墙&#xff08;之前不关也可以的&#xff0c;很奇怪&#xff09; 一句话&#xff1a;&#xff01;&#xff01;&#xff01;dhcp能自动分配IP即可联通外网&#xff01;&#xff01;&#xff01; 原理也不懂&#xff0c;或许有其他方法也不清楚&#xff0c…

采用php vue2 开发的一套医院安全(不良)事件管理系统源码(可自动生成鱼骨图)

采用php vue2 开发的一套医院安全&#xff08;不良&#xff09;事件管理系统源码&#xff08;可自动生成鱼骨图&#xff09; 医院安全&#xff08;不良&#xff09;事件管理系统采用无责的、自愿的填报不良事件方式&#xff0c;有效地减轻医护人员的思想压力&#xff0c;以事件…

项目上线流程(保姆级教学)

01&#xff1a;注册阿里云账户 02&#xff1a;登录阿里云 03&#xff1a;在桌面新建记事本保存个人账号密码等信息 04&#xff1a;完成重置密码 05&#xff1a;安装宝塔面板 命令行 yum install -y wget && wget -O install.sh http://download.bt.cn/install/instal…

Maya vs Blender:制作3D动画首选哪一个?

就 3D 动画而言&#xff0c;有两款3D软件引发了最多的争论&#xff1a;Blender 与 Maya。这两个强大的平台都提供强大的工具集&#xff0c;使动画故事和角色栩栩如生。但作为一名3D动画师&#xff0c;您应该投入时间学习和创作哪一个呢&#xff1f;下面我将从以下六点给您一个清…

spring boot中的标注@Component、@Service等

让我告诉你什么叫水货。 一、水货横行 一直以来&#xff0c;我对Spring Boot项目中的标注&#xff0c;像Component啦、Service啦、Configuration啦&#xff0c;甚至Autowired啦&#xff0c;等等&#xff0c;都似懂非懂。Autowired与Resource有什么区别也不清楚。 个中原因&a…

分享:抖音阳哥说的人力RPO项目有哪些优势?

在数字化浪潮的推动下&#xff0c;人力资源行业也迎来了前所未有的变革。抖音平台上&#xff0c;阳哥以其独到的见解和丰富的经验&#xff0c;对人力RPO(招聘流程外包)项目进行了深入解读。今天&#xff0c;我们就来探讨一下人力RPO项目究竟有哪些优势。 人力RPO项目的一大优势…

get和post的区别?get不安全-post安全|面试官:好,你走吧

get和post的区别&#xff1f;get不安全-post安全|面试官&#xff1a;好&#xff0c;你走吧 开个小玩笑&#xff0c;面试官肯定是想知道更详细的内容&#xff0c;那面下面就是相对详细的内容&#xff0c;请收下吧(*&#xffe3;︶&#xffe3;) 1、url可见性 get&#xff0c;参…

瀑布VS敏捷,看看哪种研发管理模式更适合你的团队

软件开发是一个复杂且极具挑战性的过程&#xff0c;需要有合适的研发管理模式。瀑布模型和敏捷开发是两种常见的研发管理模式&#xff0c;它们在项目管理和团队合作方面有着截然不同的理念和实践方式。本文将介绍这两种开发模式的特点、优缺点及对比&#xff0c;提供如何选择适…

【论文速读】|大语言模型(LLM)智能体可以自主利用1-day漏洞

本次分享论文&#xff1a; LLM Agents can Autonomously Exploit One-day Vulnerabilities 基本信息 原文作者&#xff1a;Richard Fang, Rohan Bindu, Akul Gupta, Daniel Kang 作者单位&#xff1a;无详细信息提供 关键词&#xff1a;大语言模型, 网络安全, 1-day漏洞, …

“我也想和月牙一样,把不满写在脸上”

贪吃蛇的初级实现 1. Win32 API介绍1.1 Win32 API1.2 控制台程序1.3 控制台屏幕上的坐标COORD1.4 GetStdHandle1.5 GetConsoleCursorInfo1.5.1 CONSOLE_CURSOR_INFO 1.6 SetConsoleCursorInfo1.7 SetConsoleCursorPosition1.8 GetAsyncKeyState 2. 贪吃蛇游戏设计与分析2.1 地图…
最新文章