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,一经查实,立即删除!

相关文章

【Unity】shader中参数传递

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

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

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

Python 实现视频去抖动技术

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

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

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

恶补《操作系统》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…

ARM功耗管理背景及挑战

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

服务器网站漏洞怎么修复

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

Linux下的基本指令(1)

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

基于 NXP iMX8MM 测试 Secure Boot 功能

By Toradex秦海 1). 简介 嵌入式设备对于网络安全的要求越来越高&#xff0c;而 Secure boot就是其中重要的一部分。 NXP i.MX8MM/i.MX8MP 处理器基于 HABv4 特性来提供 Secure boot 启动过程中的 Chain of Trust&#xff1b; HABv4 是基于公共密钥加密 (Public Key Cryptogr…

C语言进阶:指针的进阶(上)

首先 在学习新知识之前 我们先来回顾下之前的学习的内容 1 指针是个变量 用来存放地址 地址唯一标识的一块内存空间 2 指针的大小是固定的4/8字节&#xff08;32位平台/64位平台&#xff09; 3 指针有类型的 指针的类型决定了两点 一个是指针操作的权限以及整数的步长 4 指针的…

神经网络项目:全连接网络和卷积网络实现水果三分类项目

水果三分类项目 Git源码&#xff1a;传送门 水果种类&#xff1a;草莓、树莓、桑葚 0&#xff1a;草莓 strawberry1&#xff1a;树莓 raspberry2&#xff1a;桑葚 mulberry 项目设计 获取数据 spider.py数据清洗 cleaner.py自定义数据集 dataset.py网络构建 net.py训练模型 t…

git工具简单使用

文章目录 git上传克隆README.gitignore常用指令冲突 git 进行版本控制的版本控制器。安装git yum install -y git 配置git git config --global user.email "youexample.com" 告诉git你的邮箱是什么&#xff1f;最好输入你的gitee的注册邮箱git config --global …

人工智能(pytorch)搭建模型28-基于Transformer的端到端目标检测DETR模型的实际应用,DETR的原理与结构

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能(pytorch)搭建模型28-基于Transformer的端到端目标检测DETR模型的实际应用&#xff0c;DETR的原理与结构。DETR&#xff08;Detected Transformers&#xff09;是一种基于Transformer的端到端目标检测模型&…

把 KubeBlocks 跑在 Kata 上,真的可行吗?

背景 容器的安全性一直是广受关注的话题。这个领域也产生了很多不错的开源项目。Kata就是其中之一。 Kata Containers&#xff08;简称 Kata&#xff09;是一种开源项目&#xff0c;它提供了一种安全而高性能的容器运行时环境。Kata Containers 利用虚拟化技术&#xff08;通常…

【算法刷题 | 贪心算法03】4.25(最大子数组和、买卖股票的最佳时机|| )

文章目录 4.最大子数组和4.1题目4.2解法一&#xff1a;暴力4.2.1暴力思路4.2.2代码实现 4.3解法二&#xff1a;贪心4.3.1贪心思路4.3.2代码实现 5.买卖股票的最佳时机||5.1题目5.2解法&#xff1a;贪心5.2.1贪心思路5.2.2代码实现 4.最大子数组和 4.1题目 给你一个整数数组 n…

Mac下XDebug安装

文章目录 1、下载对应的版本2、编译XDebug3、配置XDebug4、配置PhpStormDebug一下 前置工作 Mac下安装HomebrewMac下brew安装php7.4 1、下载对应的版本 首先按照支持的版本和兼容性来下载对应的版本&#xff0c;此表列出了仍支持哪些 Xdebug 版本&#xff0c;以及哪些版本可用…

GPT的全面历史和演变:从GPT-1到GPT-4

人工智能新篇章&#xff1a;GPT-4与人类互动的未来&#xff01; 本文探讨了生成式预训练 Transformer (GPT) 的显着演变&#xff0c;提供了从开创性的 GPT-1 到复杂的 GPT-4 的旅程。 每次迭代都标志着重大的技术飞跃&#xff0c;深刻影响人工智能领域以及我们与技术的互动。 我…

linux+ndk把jni制作成so库供apk使用(基础)

环境配置之类的我之前的博客有写,这篇文章我们就直接开始 1.在有ndk配置的服务器创建文件夹,文件夹再创建jni文件夹,jni文件夹里面放置Application.mk,Android.mk与test.c,因为我的ndk运行配置默认是项目下面的jni目录,所以我需要多一个jni目录 2.这里的Application.mk写的是架…

OpenHarmony语言基础类库【@ohos.util (util工具函数)】

ohos.util (util工具函数) 该模块主要提供常用的工具函数&#xff0c;实现字符串编解码&#xff08;[TextEncoder])&#xff0c;[TextDecoder]&#xff09;、有理数运算&#xff08;[RationalNumber8]&#xff09;、缓冲区管理&#xff08;[LRUCache9]&#xff09;、范围判断&…