C++语法(27)--- 类型转换和C++线程库

news2024/12/26 22:18:59

C++语法(26)--- 特殊类设计_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/131879800?spm=1001.2014.3001.5501

目录

1.类型转换

1.C语言的转换模式

2.C++四种类型转换

1.static_cast

2.reinterpret_cast

3.const_cast

4.dynamic_cast

3.C++线程库

1.thread

2.线程安全

1.加锁

2.原子性

3.条件变量


1.类型转换

1.C语言的转换模式

1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
2. 显式类型转化:需要用户自己处理
 

void Test ()
{
    int i = 1;
    // 隐式类型转换
    double d = i;
    printf("%d, %.2f\n" , i, d);
    int* p = &i;
    // 显示的强制类型转换
    int address = (int) p;
    printf("%x, %d\n" , p, address);
}

缺陷:
转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换


2.C++四种类型转换

引入原因:

1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
2. 显式类型转换将所有情况混合在一起,代码不够清晰


四种类型转换:static_cast、reinterpret_cast、const_cast、dynamic_cast

这些类型是C++期望大家使用的类型转换规范

1.static_cast

多用于类型相似转换的地方,例如int和double

int main()
{
    double d = 12.34;
    int a = static_cast<int>(d);
    return 0;
}

注意圆括号在后面

2.reinterpret_cast

适用于不相关的类型之间的转换,例如int*转int
 

int main()
{
    double d = 12.34;
    int a = static_cast<int>(d);
    cout << a << endl;
    //这里使用static_cast会报错,应该使用reinterpret_cast
    //int *p = static_cast<int*>(a);
    int *p = reinterpret_cast<int*>(a);
return 0;
}

3.const_cast

const_cast最常用的用途就是删除变量的const属性

void Test ()
{
    const int a = 2;
    int* p = const_cast< int*>(&a );
    *p = 3;
    cout<<a <<endl;
    cout<<*p <<endl;
}

特别注意:调试时,监视窗口的a和*p都是3,但是最后的输出结果a为2,*p为3。

这是因为,在编译器中const类型的量会被认为是不会被修改得的,所以就会被放在栈上而不是在静态区中,随着会把a的数据放到寄存器中。修改*p其实修改了栈,也就是内存的数。而真正的a数据在寄存器中。监视窗口需要显示,所以一定会在栈上拿数据3。

void Test ()
{
    volatile const int a = 2;
    int* p = const_cast< int*>(&a );
    *p = 3;
    cout<<a <<endl;
    cout<<*p <<endl;
}

结果都为3,因为volatile保存内存可见性,不绕过内存直接读取寄存器。

4.dynamic_cast

1.向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
2.向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)


dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
1. dynamic_cast只能用于父类含有虚函数的类,拒绝父类转型子类
2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0

class A
{
public:
	virtual void f() {}
};
class B : public A
{};
void fun(A* pa)
{
	// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
	B* pb1 = static_cast<B*>(pa);
	B* pb2 = dynamic_cast<B*>(pa);
	cout << "pb1:" << pb1 << endl;
	cout << "pb2:" << pb2 << endl;
}
int main()
{
	A a;
	B b;
	fun(&a);
	fun(&b);
	return 0;
}

3.C++线程库

1.thread

 

int main()
{
	int n, m;
	cin >> n >> m;
	vector<thread>vt;
	vt.resize(n);
	for (auto& t : vt)
	{
		t = thread([m] {
			for (size_t i = 0; i < m; i++)
			{
				cout << this_thread::get_id() << ":" << i << endl;
			}
			});
	}
	for (auto& t : vt)
	{
		t.join();
	}
	return 0;
}

1.thread类型可以先不传入执行任务

2.thread中的拷贝构造delete了,所以范围for语句就不能直接t:vt即可,因为for底层调用拷贝构造,在前面加个&就不需要进行拷贝构造

3.在线程创建好后,主线程一定要记得join所有的线程,以免报错

2.线程安全

1.加锁

mutex

 try_lock:非阻塞上锁

int val = 0;
mutex mtx;

void Func(int n)
{
    mtx.lock();
	for (size_t i = 0; i < n; i++)
	{
		++val;
	}
	mtx.unlock();
}

int main()
{
	thread t1(Func,2000);
	thread t2(Func,1000);
	t1.join();
	t2.join();
	cout << val << endl;
	return 0;
}

1.为了线程安全,非原子性的全局变量进行多线程操作时,需要对该操作进行加锁

2.多线程可以执行同一份函数代码的原因是他们同时拥有函数这一公共资源。线程互相不干扰是因为线程之间有自己的独立栈结构

3.加锁进行减少执行粒度,使得时间成本减少。要考虑是否频繁获取上下文,执行代码是否繁琐。

recursive_mutex:递归互斥锁,递归调用锁的函数,使得不自己把自己阻塞。判断是增加条件当前的线程和上一层递归的线程的地址是否一致。

lock_guard

int main()
{
	mutex mtx;
	atomic<int> aval;
	auto func = [&aval, &mtx](int n) {
		{
			lock_guard<mutex> lock(mtx);
			cout << this_thread::get_id() << "->" << val << endl;
		}
		aval++;
	};
	thread t1(func, 2000);
	thread t2(func, 1000);
	t1.join();
	t2.join();
	cout << aval << endl;
	return 0;
}

2.原子性

CAS:Compare and Swap

CAS的原理:三个参数,一个当前内存值V、旧的预期值A、即将更新的值B。两个线程存储的都为A,想要对V进行修改。当一个线程同时修改内存值时,V会被临时存储起来,修改后同步内存,此时另一个也进行修改,那么就会被比较当前另一个的A和当前修改的V,一旦对不上,则另一个线程就会等待之前修改的线程先更新。

atomic

 

atomic<int> aval;

void Func(int n)
{
	for (size_t i = 0; i < n; i++)
	{
		++aval;
	}
}

int main()
{
	thread t1(Func, 2000);
	thread t2(Func, 1000);
	t1.join();
	t2.join();
	cout << aval << endl;
	return 0;
}

3.条件变量

两个线程,交替打印,一个打印奇数,一个打印偶数

模型一:

int main()
{
	int i = 0;
	thread t1([&i]{
		while (i < 100)
		{
			if (i % 2 == 0)
			{
				cout << this_thread::get_id() << "->" << i << endl;
				++i;
			}
		}
	});

	thread t2([&i] {
		while (i <= 100)
		{
			if (i % 2 == 1)
			{
				cout << this_thread::get_id() << "->" << i << endl;
				++i;
			}
		}
		});

	t1.join();
	t2.join();
	return 0;
}

缺点:当一个数不是if条件,那么它就会不断的循环while,直到if条件满足,这样的做法极大程度浪费了事件,因为我们在执行彼此任务同时,还需要对方不断的循环判断是否满足条件。

模型二:

条件变量 -- condition_variable

wait:等待通知

notify:发送通知

条件变量本身不是线程安全的,想要配合锁实现。

//线程交替打印
int main()
{
	int i = 0;
	mutex mtx;
	condition_variable cv;
	bool flag = true;

	//奇数  flag==false
	thread t1([&]{
		while (i < 100)
		{
			unique_lock<mutex> lock(mtx);
			while(flag==true)
				cv.wait(lock);

			cout << "t1:" << this_thread::get_id() << "->" << i << endl;
			++i;
			flag = true;
			cv.notify_one();
		}
	});

	//偶数  flag==true
	thread t2([&] {
		while (i <= 100)
		{
			unique_lock<mutex> lock(mtx);
			while (flag == false)
				cv.wait(lock);

			cout << "t2:" << this_thread::get_id() << "->" << i << endl;
			++i;
			flag = false;
			cv.notify_one();
		}
	});

    /*
    thread t1([&]{
		while (i < 100)
		{
			unique_lock<mutex> lock(mtx);
			while(i%2)
				cv.wait(lock);

			cout << "t1:" << this_thread::get_id() << "->" << i << endl;
			++i;
			cv.notify_one();
		}
	});

	//偶数  flag==true
	thread t2([&] {
		while (i <= 100)
		{
			unique_lock<mutex> lock(mtx);
			while (!(i%2))
				cv.wait(lock);

			cout << "t2:" << this_thread::get_id() << "->" << i << endl;
			++i;
			cv.notify_one();
		}
	});
    */

	t1.join();
	t2.join();
	return 0;
}

分析:该方式不会自旋的判断,一旦条件成立,通知就会唤醒线程。这样就不会占用cpu运行了。

pred的使用:

第二个wait函数的pred用于判断,如果pred返回false则会阻塞

	thread t1([&]{
		while (i < 100)
		{
			unique_lock<mutex> lock(mtx);
			cv.wait(lock, [&i] {return i % 2; });
			cout << "t1:" << this_thread::get_id() << "->" << i << endl;
			++i;
			cv.notify_one();
		}
	});

	thread t2([&] {
		while (i <= 100)
		{
			unique_lock<mutex> lock(mtx);
			cv.wait(lock, [&i] {return !(i % 2); });
			cout << "t2:" << this_thread::get_id() << "->" << i << endl;
			++i;
			cv.notify_one();
		}
	});

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

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

相关文章

ALLEGRO之Logic

本文主要讲述ALLEGRO的Logic菜单。 &#xff08;1&#xff09;Net Logic&#xff1a;暂不清楚&#xff1b; &#xff08;2&#xff09;Net Schedule&#xff1a;暂不清楚&#xff1b; &#xff08;3&#xff09;AssignDifferential Pair&#xff1a;暂不清楚&#xff1b; &a…

OR-Tool 报INFEASIBLE

OR-Tool 使用Minimum Cost Flows报 There was an issue with the min cost flow input. Status: Status.INFEASIBLE 这是因为node的编号需要是连续的&#xff0c;比如下面这样不行 修改为连续的

【已解决】如果将MySQL数据库中的表生成PDM

数据库表PDM关系图 | 原创作者/编辑&#xff1a;凯哥Java | 分类&#xff1a;经验分享 有时候&#xff0c;我们需要MySQL数据库中的表生成对应的PDM文件&#xff0c;这里凯哥就讲讲第一种将MySQL数据库的表生成对应的PDM文件。 环境准备&#xff1a; MySQL数据库连接客户端&…

中文多模态医学大模型智能分析X光片,实现影像诊断,完成医生问诊多轮对话

项目设计集合&#xff08;人工智能方向&#xff09;&#xff1a;助力新人快速实战掌握技能、自主完成项目设计升级&#xff0c;提升自身的硬实力&#xff08;不仅限NLP、知识图谱、计算机视觉等领域&#xff09;&#xff1a;汇总有意义的项目设计集合&#xff0c;助力新人快速实…

费舍尔线性分辩分析(Fisher‘s Linear Discriminant Analysis, FLDA)

费舍尔线性分辩分析(Fisher’s Linear Discriminant Analysis, FLDA) 目录 费舍尔线性分辩分析(Fishers Linear Discriminant Analysis, FLDA)1. 问题描述2. 二分类情况3. 多分类情况4. 代码实现4.1 二分类情况4.2 多分类情况 5. 参考资料 1. 问题描述 为解决两个或多个类别的…

ROS-PyQt小案例

前言&#xff1a;目前还在学习ROS无人机框架中&#xff0c;&#xff0c;&#xff0c; 更多更新文章详见我的个人博客主页【前往】 ROS与PyQt5结合的小demo&#xff0c;用于学习如何设计一个界面&#xff0c;并与ROS中的Service和Topic结合&#xff0c;从而控制多个小乌龟的运动…

从零开始搭建Vue3框架(二):Vue-Router4.0使用与配置

前言 上篇文章我们创建了模板项目并成功运行&#xff0c;但是运行后的页面只是一个静态页面&#xff0c;并没有页面间跳转。 对于Vue这种单页应用来说&#xff0c;最要紧的就是控制整个系统的页面路由。因为我们使用Vue3的框架&#xff0c;所以这里使用Vue-Router4.0版本。 …

1992-2021年全国及31省对外开放度测算数据含原始数据和计算过程(无缺失)

1992-2021年全国及31省对外开放度测算数据含原始数据和计算过程&#xff08;无缺失&#xff09; 1、时间&#xff1a;1992-2021年 2、范围&#xff1a;全国及31省 3、指标&#xff1a;进出口总额、国内生产总值、年均汇率 4、计算方法&#xff1a;对外开放度进出口总额/GDP…

【Git系列】Git配置SSH免密登录

&#x1f433;Git配置SSH免密登录 &#x1f9ca;1.设置用户名和邮箱&#x1f9ca;2. 生成密钥&#x1f9ca;3.远程仓库配置密钥&#x1f9ca;2. 免密登录 在以上push操作过程中&#xff0c;我们第一次push时&#xff0c;是需要进行录入用户名和密码的&#xff0c;比较麻烦。而且…

【数据分析专栏之Python篇】四、pandas介绍

前言 在上一篇中我们安装和使用了Numpy。本期我们来学习使用 核心数据分析支持库 Pandas。 一、pandas概述 1.1 pandas 简介 Pandas 是 Python 的 核心数据分析支持库&#xff0c;提供了快速、灵活、明确的数据结构&#xff0c;旨在简单、直观地处理关系型、标记型数据。 …

Resnet与Pytorch花图像分类

1、介绍 1.1数据集介绍 flower_data├── train│ └── 1-102&#xff08;102个文件夹&#xff09;│ └── XXX.jpg&#xff08;每个文件夹含若干张图像&#xff09;├── valid│ └── 1-102&#xff08;102个文件夹&#xff09;└── ─── └── XXX.jp…

如何使用免费敏捷工具Leangoo领歌管理Sprint Backlog

什么是Sprint Backlog&#xff1f; Sprint Backlog是Scrum的主要工件之一。在Scrum中&#xff0c;团队按照迭代的方式工作&#xff0c;每个迭代称为一个Sprint。在Sprint开始之前&#xff0c;PO会准备好产品Backlog&#xff0c;准备好的产品Backlog应该是经过梳理、估算和优先…

ffmpeg安装

简介 FFmpeg是一个开源的音视频处理库&#xff0c;它提供了一系列的工具和API&#xff0c;可以用于处理音视频文件。你可以使用FFmpeg的命令行工具来执行各种音视频处理操作&#xff0c;比如转码、剪辑、合并等。FFmpeg的命令格式通常是&#xff1a;ffmpeg [全局选项] {[输入文…

章节5:SQL注入之WAF绕过

章节5&#xff1a;SQL注入之WAF绕过 5.1 SQL注入之WAF绕过上 WAF拦截原理&#xff1a;WAF从规则库中匹配敏感字符进行拦截。 5.2 SQL注入之WAF绕过下 &#xff08;原理简单了解&#xff09; 关键词大小写绕过 有的WAF因为规则设计的问题&#xff0c;只匹配纯大写或纯小写的…

B. Binary Cafe(二进制的妙用)

题目&#xff1a;Problem - B - Codeforces 总结&#xff1a; 对于该题最简单的方法为使用二进制的数表示状态 例如&#xff1a; 对于一个数7的二进制&#xff1a;111 它的每一位都可表示两种状态我们可以理解为取或者不取 对于7这个数字它可以表示一种状态即在三个位置都…

使用Roles模块搭建LNMP架构

使用Roles模块搭建LNMP架构 1.Ansible-playbook中部署Nginx角色2.Ansible-playbook中部署PHP角色3.Ansible-playbook中部署MySQL角色4.启动安装分布式LNMP 1.Ansible-playbook中部署Nginx角色 创建nginx角色所需要的工作目录&#xff1b; mkdir -p /etc/ansible/playbook/rol…

剖析 Kubernetes 控制器:Deployment、ReplicaSet 和 StatefulSet 的功能与应用场景

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

【kubernetes】k8s单master集群环境搭建及kuboard部署

k8s入门学习环境搭建 学习于许大仙: https://www.yuque.com/fairy-era k8s官网 https://kubernetes.io/ kuboard官网 https://kuboard.cn/ 基于k8s 1.21.10版本 前置环境准备 一主两从&#xff0c;三台虚拟机 CPU内存硬盘角色主机名IPhostname操作系统4C16G50Gmasterk8s-mast…

JSON动态生成表格

<!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><script>var fromjava"{\"total\":3,\"students\":[{\"name\":\"张三\",\&q…

哔哩哔哩缓存转码|FFmpeg将m4s文件转为mp4|PHP自动批量转码B站视频

window下载安装FFmpeg 打开ffMpeg官网选择window>Windows builds from gyan.dev 打开https://www.gyan.dev/ffmpeg/builds/ 这里是上面提取的下载链接如果过期不能用自己去官网下 配置FFmpeg环境变量 上面下载的FFmpeg是绿色软件&#xff0c;下载解压到你的常用软件安装目…