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 posprev->_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 posprev->_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.mzph.cn/bicheng/3249.shtml

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

相关文章

Python数据权限的管理通常涉及到几个关键组件:身份验证,、授权和访问控制。这通常是通过使用数据库、ORM(对象关系映射)框架、API框架和中间件

在Python中&#xff0c;数据权限的管理通常涉及到几个关键组件&#xff1a;身份验证&#xff0c;、授权和访问控制。这通常是通过使用数据库、ORM&#xff08;对象关系映射&#xff09;框架、API框架和中间件等技术来实现的。以下是一些建议的步骤和工具&#xff0c;用于在Pyth…

C语言面经

25.类型相同的两个指针之间不能进行的运算 指针主要用于存储变量的内存地址。对于同类型的指针变量之间&#xff0c;有一些规则&#xff1a; a. 小于运算&#xff08;<&#xff09;&#xff1a;指针间的小于比较是基于它们指向的内存地址。地址较小的指针在小于比较中被认为…

【Unity】shader中参数传递

1、前言 unity shader这个对于我来说是真的有点难&#xff0c;今天这篇文章主要还是总结下最近学习到的一些东西&#xff0c;避免过段时间忘记了&#xff0c;可能有不对&#xff0c;欢迎留言纠正。 2、参数传递的两种方式 2.1 语义传递 语义传递这个相对来说是简单的 shad…

Csharp_pta2_2

7-7 C# 1.12 区间找数 编写控制台应用程序&#xff0c;根据用户输入的a、b、c、d值&#xff08;均为正整数且a不大于b&#xff09;&#xff0c;输出在[a, b]区间中能被c整除&#xff0c;但是不能被d整除的数。 输入格式: 用户在一行中输入四个正整数&#xff0c;分别对应a、…

数组模拟几种基本的数据结构

文章目录 数组模拟单链表数组模拟双链表数组实现栈数组模拟队列总结 数组模拟单链表 首先类比结构体存储单链表&#xff0c;我们需要一个存放下一个节点下标的数组&#xff0c;还需要一个存储当前节点的值的数组&#xff0c;其次就是一个int类型的索引&#xff0c;这个索引指向…

Python 实现视频去抖动技术

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 视频去抖动是视频处理中的一项重要技术&#xff0c;它可以有效地减少视频中由于相机震动或手…

springSecurity简单直接说明

引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombo…

MyBatis处理SQL中的特殊字符

方式一&#xff1a;转义字符 如下案例&#xff1a; < 表示小于的转义字符 <!-- 在Mapper XML文件中定义SQL语句 --> <select id"selectById" resultMap"BaseResultMap">select *from userwhere id < #{id}; </select>方式二&am…

设计模式:依赖倒转原则(Dependency Inversion Principle,DIP)介绍

依赖倒转原则&#xff08;Dependency Inversion Principle&#xff0c;DIP&#xff09;是面向对象设计原则之一&#xff0c;它强调高层模块不应该依赖于底层模块&#xff0c;二者都应该依赖于抽象。同时&#xff0c;抽象不应该依赖于具体实现细节&#xff0c;具体实现细节应该依…

嵌入式开发学习--进程、线程

什么是进程 进程和程序的区别 概念 程序&#xff1a;编译好的可执行文件&#xff0c;存放在磁盘上的指令和数据的有序集合&#xff08;文件&#xff09;&#xff0c;程序是静态的&#xff0c;没有任何执行的概念。 进程&#xff1a;一个独立的可调度的任务&#xff0c;执行一…

高可靠性部署系列(3)--- ASG双机热备(HA)

高可靠性部署系列(3)--- ASG双机热备(HA) 前言网络拓扑设备选型网络规划组网需求配置思路操作步骤步骤 1 HA接口管理地址配置步骤 2 HA全局配置步骤 3 配置同步步骤 4 接口状态同步组创建结果验证前言 近期有读者留言:“因华为数通模拟器仅能支持USG6000V的防火墙,无法支…

东方博宜1009 - 数组逆序

题目描述 给你 nn 个整数&#xff0c;将其逆序输出。 输入 第一行一个整数 nn &#xff08;3 \le n \le 1003≤n≤100)代表数的个数。 第二行 nn 个整数&#xff08;空格隔开&#xff09;&#xff08;这些数在 0 \sim 10^60∼106 之间)。 输出 nn 个整数&#xff08;空格…

恶补《操作系统》3_1——王道学习笔记

3内存管理 3.1_1 内存的基础知识 1、什么是内存&#xff0c;作用 &#xff08;1&#xff09;内存&#xff1a;内存用来存放数据。程序执行前需要先放到内存中才能被CPU处理――缓和CPU与硬盘之间的速度矛盾。 &#xff08;2&#xff09;内存存储单元&#xff1a;每个地址对应…

AIGC技术的发展现状和未来趋势

AIGC&#xff08;人工智能生成内容&#xff09;技术是指利用人工智能算法自动生成文本、图像、音频、视频等各类内容的技术。随着深度学习等技术的快速发展&#xff0c;AIGC技术在最近几年取得了显著进步&#xff0c;并在多个领域展现出巨大的潜力。 ​ 编辑 发展现状&#x…

前端数字计算精度问题

计算精度问题通常发生在浮点数运算中&#xff0c;由于浮点数的表示所限&#xff0c;可能导致精度损失。 举例 // 比如 0.1 0.2 // 结果为 0.30000000000000004 0.3 - 0.1 // 结果为 0.19999999999999996vue vue 使用decimal.js 解决小数相加合计精确度丢失问题 微信小程序 …

【2024系统架构设计】回顾历史,查缺补漏篇 ①

前言 hello,大家好: 💡💡💡 我们一起来备考软考高级系统架构设计师吧,本专栏提供综合知识、案例科目、论文(论点和部分示例范文)等内容,包括知识点总结和记忆小妙招哦。 🚀🚀🚀 可以减少资料查找和收集的时间,提高效率,我们一起

ARM功耗管理背景及挑战

安全之安全(security)博客目录导读

服务器网站漏洞怎么修复

服务器网站漏洞的修复是一个关键且复杂的过程&#xff0c;涉及到多个层面的安全加固。以下是一个关于如何修复服务器网站漏洞的详细指南。安全狗专业做服务器安全&#xff0c;有任何服务器安全问题都可以找安全狗哦. ​一、识别和分析漏洞 首先&#xff0c;要确定服务器网站存在…

基于NodeJS + Swagger UI搭建Web API界面

基于NodeJS Swagger UI搭建Web API界面 前言一、创建基于NodeJS的Swagger运行目录二、添加Swagger官方的示例1.创建public工作目录2.添加Swagger官方示例3.启动SwaggerUI实例 三、基于OpenAPI规范提供api文档 前言 Swagger是一个REST APIs文档在线自动生成和测试的框架 一、…

Linux下的基本指令(1)

嗨喽大家好呀&#xff01;今天阿鑫给大家带来Linux下的基本指令&#xff08;1&#xff09;&#xff0c;下面让我们一起进入Linux的学习吧&#xff01; Linux下的基本指令 ls 指令pwd命令cd 指令touch指令mkdir指令(重要)rmdir指令 && rm 指令(重要)man指令(重要)cp指…