C++编程(三)—— C++11

news2024/9/23 1:37:05

文章目录

  • 绑定器和函数对象
    • 函数对象
    • 绑定器
    • lambda表达式
  • 关键词与语法
    • auto
    • nullptr
    • 右值引用
  • 智能指针
  • 容器
    • set和map
    • unordered_set和unordered_map
    • 数组
    • 链表
  • 语言级别支持的多线程编程
    • thread
    • 子线程如何结束
    • 主线程如何处理子线程
    • 线程间的互斥
    • 线程的同步通信机制(条件变量)
    • 总结


绑定器和函数对象

函数对象

使用函数对象时,不需要事先定义一个类。

例子:优先级队列:

priority_queue<int, vector<int>, greater<int>> ay;

当你使用 greater<int> 时,你实际上是在创建一个 greater<int> 的实例,而不是调用一个函数。在这种情况下,不需要使用括号。括号通常用于调用函数,而不是创建函数对象的实例。

排序算法:

std::sort(vec.begin(), vec.end(), std::greater<int>());

greater 是一个函数对象类,它定义了一个函数调用运算符 operator(),用于比较两个元素的大小。

然而,如果你要使用函数对象来进行比较操作,你需要使用括号来调用该函数对象的函数调用运算符 operator()。这个函数调用运算符是函数对象类中的一个成员函数,用于执行比较操作。例如:

greater<int> comp;
bool result = comp(5, 10);  // 调用函数对象的函数调用运算符

在上面的示例中,comp 是greater<int> 的一个实例,通过调用函数对象的函数调用运算符,可以将 5 和 10 进行比较。

需要注意的是, std::greater<int>() 是一个二元函数对象,可以被用于比较两个值的大小。
如果 std::greater() 是一个一元函数对象,它将无法正确地用作 std::sort 的比较器。因为 std::sort 需要一个接受两个参数的比较函数对象来进行排序操作

但是在优先队列的模板参数中,我们只需提供函数对象类型,而不需要调用它的函数调用运算符。优先队列会在内部使用这个函数对象进行比较操作。因此,在优先队列的模板参数中,我们只需提供函数对象的类型 greater<int>,而不需要调用它。

绑定器

函数绑定器(Function binders)是一种函数适配器

bind1st和bind2nd在STL中主要用于二元函数对象,将其中的一元绑定成一个固定的量,成为一元函数变量。
bind1st和bind2nd+二元函数对象 =》 一元函数对象

greater<int>为例,如果我现在想在一个已经排序完成的数组vec中在正确的位置插入70,可以使用bind1st绑定

70按顺序插入vec容器中--》找一个小于70的数字
operator()(const T &val)
greater   a > b
less      a < b

auto it1 = find_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70);auto it1 = find_if(vec.begin(), vec.end(), bind2nd(less<int>(), 70);
if(it1 != vec.end())
{
	vec.insert(it1, 70);
}

bind是bind1st和bind2nd的升级,他们本身也是函数对象。

#include <iostream>
#include <functional>

void printValues(int a, int b) {
    std::cout << "a: " << a << ", b: " << b << std::endl;
}

int main() {
    // 使用 std::bind1st
    auto printA = std::bind1st(std::ptr_fun(printValues), 42);
    printA(10);  // 输出:a: 42, b: 10

    // 使用 std::bind2nd
    auto printB = std::bind2nd(std::ptr_fun(printValues), 20);
    printB(30);  // 输出:a: 30, b: 20

    // 使用 std::bind
    auto printC = std::bind(printValues, std::placeholders::_1, std::placeholders::_2);
    printC(50, 60);  // 输出:a: 50, b: 60

    return 0;
}

lambda表达式

关键词与语法

详情见:博客

auto

根据右值,推导出右值的类型

nullptr

指针专用。(之前的NULL指针和整数是混用的)

右值引用

move移动语义函数和forward类型完美转发函数

智能指针

详情见:博客

shared_ptr和weak_ptr

容器

详情见:博客

set和map

增删插的效率很高
红黑树为底层,有序容器

unordered_set和unordered_map

哈希表为底层,增删插的效率为O(1)

数组

array
vector 建议使用

链表

farword_list双向链表
list 建议使用

语言级别支持的多线程编程

概念见:博客

之前都是使用的操作系统的接口,如:
createThread pthread_create clone
这样对跨平台很不友好,兼容性差。

thread

int main
{
	// 创建了一个线程对象,传入一个线程函数,新线程就开始运行了
	std::thread t1(threadHandle1, 2);
	
	xxxxx  主程序
	
	// 主线程等待子线程结束,主线程继续往下运行
	//t1.join();
	
	//把子线程设置为分离线程
	t1.detach();
	
	cout << "main thread done!" << endl;
	当主线程运行完成时,如果查看当前进程还有未运行完成的子线程,进程就会异常终止
	return 0;
}

子线程如何结束

子线程函数运行完成,线程结束

主线程如何处理子线程

1、主线程等待子线程结束 join

2、把子线程设置为分离线程,不管子线程 detach

线程间的互斥

竞争态条件,有不是线程安全的代码=》临界区代码段=》保障原子操作=》互斥锁mutex
在这里插入图片描述
所以临界区代码需要=》操作=》互斥锁
锁+双重判断
在这里插入图片描述

线程的同步通信机制(条件变量)

场景:线程1必须依赖线程2的通知

例子:生产者消费者模型
1、创建线程安全的lockQueue
在这里插入图片描述

std::mutex mtx; // 定义互斥锁,做线程间的互斥操作
std::condition_variable cv; // 定义条件变量,做线程间的同步通信操作

// 生产者生产一个物品,通知消费者消费一个;消费完了,消费者再通知生产者继续生产物品
class Queue   // 对queue重新封装一下
{
public:
	void put(int val) // 生产物品
	{
		//lock_guard<std::mutex> guard(mtx); // scoped_ptr   不能同时使用两把锁
		unique_lock<std::mutex> lck(mtx); // unique_ptr
		while (!que.empty())
		{
			// que不为空,生产者应该通知消费者去消费,消费完了,再继续生产
			// 生产者线程进入#1等待状态(阻塞状态),并且#2把mtx互斥锁释放掉 消费者线程就能抢到这把锁   不释放锁  无法消费
			cv.wait(lck);  // lck.lock()  lck.unlock
		}
		que.push(val);
		/* 
		notify_one:通知另外的一个线程的
		notify_all:通知其它所有线程的
		通知其它所有的线程,我生产了一个物品,你们赶紧消费吧
		其它线程得到该通知,就会从等待状态 =》 阻塞状态 =》 获取互斥锁才能继续执行
		*/
		cv.notify_all(); 
		cout << "生产者 生产:" << val << "号物品" << endl;
	}
	int get() // 消费物品
	{
		//lock_guard<std::mutex> guard(mtx); // scoped_ptr
		unique_lock<std::mutex> lck(mtx); // unique_ptr
		while (que.empty())
		{
			// 消费者线程发现que是空的,通知生产者线程先生产物品
			// #1 进入等待状态 # 把互斥锁mutex释放
			cv.wait(lck);
		}
		int val = que.front();
		que.pop();
		cv.notify_all(); // 通知其它线程我消费完了,赶紧生产吧
		cout << "消费者 消费:" << val << "号物品" << endl;
		return val;
	}
private:
	queue<int> que;
};
void producer(Queue *que) // 生产者线程  生产10个物品
{
	for (int i = 1; i <= 10; ++i)
	{
		que->put(i);
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
}
void consumer(Queue *que) // 消费者线程
{
	for (int i = 1; i <= 10; ++i)
	{
		que->get();
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
}
int main()
{
	Queue que; // 两个线程共享的队列

	std::thread t1(producer, &que);
	std::thread t2(consumer, &que);

	t1.join(); // 主线程等到两个子线程执行完  继续执行
	t2.join();
    
	return 0;
}


总结

线程间互斥 : 临界区 原子类型 互斥锁 信号量

线程间同步 : 条件变量 信号量

1、std::mutex

std::mutex mtx;
mtx.lock()
mtx.unlock()

2、lock_guard
只能在简单的临界区代码段的互斥操作中,不可能用在函数参数传递或者返回函数中。
因为函数参数传递或者返回过程中都会用到拷贝构造和赋值,但是lock_guard拷贝构造和赋值(引用和右值引用)都被delete了。

lock_guard<std::mutex> guard(mtx)

3、unique_lock
不仅能在简单的临界区代码段的互斥操作中,还能用在函数参数传递(函数调用)中。
虽然unique_lock底层左值引用的拷贝构造和赋值被delete,但是它提供了右值引用的拷贝构造和赋值

unique_lock<std::mutex> lck(mtx)

4、条件变量

std::condition_variable cv;
cv.wait(lck);   //guard输入不了,因为lock_guard没有拷贝构造
// 使线程进入等待状态,并且把lck.unlock可以把mtx释放掉
cv.notify_all();
// 通知再cv上等待的线程,条件成立了,起来干活了
// 收到通知=》从等待状态到阻塞状态=》获取互斥锁了=》线程继续执行
notify_one();
// 通知再cv上等待的一个线程

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

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

相关文章

Windows Cluster 分布式算法

在分布式系统中&#xff0c;都需要解决分布式一致性问题。那么&#xff0c;在Windows 集群中&#xff0c;使用了什么算法来保证集群的一致性呢——Paxos。Windows Server 故障转移集群 (WSFC) 使用 Paxos 算法在整个系统中同步更改。通过记录 Paxos Tag 值并保留历史记录&#…

连锁门店如何搭建B2B2C多用户商城系统?

现在很多的线下店铺都开始慢慢的转型线上了&#xff0c;想线上线下相结合&#xff0c;但是最近很多的商家都在问什么样的B2B2C商城系统开发适合线下店铺呢?这个问题今天加速度jsudo小编给大家一起整理如下&#xff0c;相信商家看完后就知道如何选择一款合适的商城系统了。 一、…

【C语言】求序列前N项和

问题描述 输入一个正整数n&#xff0c;输出2/13/25/38/5…的前n项之和&#xff08;该序列从第2项起&#xff0c;每一项的分子是前一项分子与分母的和&#xff0c;分母是前一项的分子&#xff09;&#xff0c;保留2位小数。试编写相应程序。 代码实现 #include<stdio.h>…

spring-14优化性能

原始Junit测试Spring的问题 这里的&#xff1a;第一行代码获得应用上下文对象&#xff0c;第二行代码获得你那个对象 2、原先测试找junit&#xff0c;现在测试找spring&#xff0c;然后再找&#xff0c;junit&#xff0c;告诉我配置文件是什么&#xff0c;然后注入测试对象&am…

LeetCode 172.阶乘后的零

基础方法就是暴力解&#xff0c;其次是数学归纳。 具体思路如下&#xff1a;&#xff08;copy大佬的&#xff09; 耐心看完&#xff01; 代码如下&#xff1a; #include <iostream> #include <vector> #include <cmath> #include <algorithm> #incl…

Android GridPager实战,从RecyclerView to ViewPager

这个简单的的案例展示了如何从RecyclerView to ViewPager&#xff0c;以网上的公开图片为样例。 安卓开发中从RecyclerView 到 ViewPager demo运行结果demo项目工程目录结构关键代码 MainActivity关键代码GridFragment关键代码ImageFragment关键代码ImagePagerFragment关键布局…

关于示波器引入50HZ工频干扰的解释

前几天&#xff0c;小白在实验室工作时&#xff0c;听到同事抱怨示波器有问题。上前查看&#xff0c;才知道&#xff0c;小白的那位同事在测量信号波形时&#xff0c;实际与理想相差甚远。于是乎&#xff0c;在探头什么也不接的情况下&#xff0c;发现示波器本身也存在波形信号…

2022Robocom国赛-u2 女王的大敕令

副本是游戏里的一个特色玩法&#xff0c;主要为玩家带来装备、道具、游戏资源的产出&#xff0c;满足玩家的游戏进程。 在 MMORPG《最终幻想14》里&#xff0c;有一个攻略人数最大达到 48 人的副本“零式贡希尔德神庙”&#xff0c;其中守关 BOSS “天佑女王”有一个很有趣的技…

图形编辑器开发:一些会用到的简单几何算法

大家好&#xff0c;我是前端西瓜哥。 开发图形编辑器&#xff0c;你会经常要解决一些算法问题。本文盘点一些我开发图形编辑器时遇到的简单几何算法问题。 矩形碰撞检测 判断两个矩形是否发生碰撞&#xff08;或者说相交&#xff09;&#xff0c;即两个矩形有重合的区域。 …

C生万物 | 程序员必备实用调试技巧分享

一起来学习调试~ 一、前言二、什么是Bug&#xff1f;三、调试是什么&#xff1f;有多重要&#xff1f;1、导学引入2、调试的基本步骤3、Debug和Release的介绍 四、Windows环境下VS调试介绍1、调试环境的准备2、学会快捷键3、调试的时候查看程序当前信息3.1 查看临时变量的值3.2…

基于SSM的购物商城系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

SpringBoot中通过自定义Jackson注解实现接口返回数据脱敏

场景 SpringBoot中整合Sharding Sphere实现数据加解密/数据脱敏/数据库密文&#xff0c;查询明文&#xff1a; SpringBoot中整合Sharding Sphere实现数据加解密/数据脱敏/数据库密文&#xff0c;查询明文_霸道流氓气质的博客-CSDN博客 上面讲的是数据库中存储密文&#xff0…

音乐格式转换mp3软件有哪些?分享三个方法给大家!

要将音乐文件转换为MP3格式的情况&#xff0c;以便在各种设备上播放。为了帮助大家完成这个任务&#xff0c;下面将分享三种实用的方法和工具&#xff0c;其中方法一是使用记灵在线工具进行音乐格式转换。无论您是音乐爱好者还是需要将音频文件转换为MP3格式的专业人士&#xf…

障碍物距离显示需求功能定义

1. 需求 来源 整车功能定义清单中SAF-10 -06 条需求 。泊车视觉辅助 &#xff0c;360全景 -距离树数值显示时&#xff0c;显示车辆与障碍物的距离数字 。 2. 开发 范围 项目带全景功能的配置&#xff0c;见最新配置表&#xff1a; 3. 功能 定义 在雷达报警激活状态下&#xff0…

SSM入门—Spring框架-IOC简单案例

目录 控制反转&#xff1a;创建对象 基于XML实现 基于注解实现 依赖注入&#xff1a;对象赋值 通过xml注入 控制反转&#xff1a;创建对象 把对象的创建权交给了Spring容器 基于XML实现 1、maven 导入依赖 <!--Maven会自动添加当前jar依赖的其他jar--> <depen…

第一章 数据库的操作

第一章 数据库的操作 一、库的操作1、创建数据库&#xff08;1&#xff09;语法&#xff08;2&#xff09;字符集与校验规则a.定义 &#xff08;3&#xff09;创建不同字符集与校验规则的数据库 2、查看数据库&#xff08;1&#xff09;语法&#xff08;2&#xff09;示例 3、显…

自定义类型——结构体,枚举,联合(详,真的太详了)

一.结构体 1.1什么是结构体&#xff0c;结构体如何声明和定义变量&#xff1f; 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量。 struct 变量名 { 不同类型的成员变量&#xff1b; }&#xff1b; 一定要记得在花括号的后面加上分…

5.4 python内置高阶函数之--map、reduce、filter、sorted

高阶函数满足条件&#xff1a;1、 函数名被作为参数传给另外一个函数2、 函数返回值为另外一个函数&#xff08;返回为自己&#xff0c;则为递归&#xff09;一、 高阶函数&#xff1a;map 【 map函数】说明可以去查看源码&#xff0c; 会发现&#xff1a;map的__init__中有两个…

deeplabv3+源码之慢慢解析 第二章datasets文件夹(3)cityscapes.py--Cityscapes类

系列文章目录&#xff08;更新中&#xff09; 第一章deeplabv3源码之慢慢解析 根目录(1)main.py–get_argparser函数 第一章deeplabv3源码之慢慢解析 根目录(2)main.py–get_dataset函数 第一章deeplabv3源码之慢慢解析 根目录(3)main.py–validate函数 第一章deeplabv3源码之…

MyBatis-Plus学习总结

目录 1.MyBatis-Plus介绍 2.第一个MyBatis-Plus程序 3.配置日志输出 4. 主键生成策略 4.1 ID_WORKER -- 雪花算法 4.2 主键生成策略 -- 详情 5. 自动填充 6.MyBatis-Plus的CRUD 6.1 insert -- 插入 6.2 delete -- 删除 6.3 update -- 更新 6.4 select -- 查询 7. …