【c++】异常详解
目录
- C语言处理错误的局限性
- 异常的定义
- 异常的具体使用细则
- 异常的抛出与捕获
- 在函数调用链中异常栈展开匹配原则
- 异常的重新抛出
- 异常规范
- throw(类型)
- noexcept
- 成熟的异常体系
- c++自己的异常体系
- 异常的优缺点
- 优点
- 缺点
- 异常安全
C语言处理错误的局限性
C语言处理错误常常会用到assert和打印错误码这两种方式。assert可以在检测到错误之后立刻终止程序报错,但是assert只会在debug版才会奏效,release版就不会产生效果了,C语言期望程序员在代码测试阶段就完成对全部错误的排查,太过于理想。此外,终止程序的方式也太过于暴力,试想一下生活中我们使用的程序或网站因为一个小掉线就直接报错终止,未免太过于大惊小怪,使用体验很糟糕。而对于打印错误码的方式,首先打不会直接终止程序,也不会在release版失效,这两点看起来很好。c语言错误码是通过全局变量的方式实现的,程序有异常,就会将错误码传给errno(C语言规定的错误码,是一个全局变量),这时可以通过调用perror函数等方式打印错误码,但是这种方式打印的错误码可读性很差,且error作为全局变量需要及时打印,不然下一个错误出来就会被覆盖,这样就要写很多if语句打印错误码,倘若想要使用函数返回统一处理也要一层一层的返回很麻烦,忘记返回也不会报错,就会出现纰漏。总而言之,c语言的这套处理错误的方式还是很麻烦的,所以c++引入了异常来替代这种方式。
异常的定义
异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的直接或间接的调用者处理这个错误。
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>using namespace std;void func()
{throw "func() error";
}int main()
{try{func();}catch (const char* x){cout << x << endl;}return 0;
}
这就是抛异常的一个简单的使用场景。场景中有三个异常中会使用到的关键字,分别是:
1.throw:判断当前程序出现异常时用来抛出异常所使用的。
2.try:try块中的代码会标识将要被激活的特定异常,它后面通常跟着一个或多个 catch 块。try块中的代码被称为保护代码。
3.catch: 在想要处理问题的地方,通过异常处理程序捕获异常,catch 关键字用于捕获异常,可以有多个catch进行捕获。
异常的具体使用细则
异常的抛出与捕获
异常使用throw关键字抛出,c++支持抛出任意类型的异常,而抛出的异常的类型会与对应try块的catch块的参数所匹配(参数只用来匹配的话可以只写类型),匹配成功执行流就会进入该catch块内部,由于抛出的对象只有一个,所以catch块的参数也就只会有一个。
一个try块是可以有多个catch块的,所有抛出的异常会与对应try块的所有catch块自上而下按照顺序匹配,找到第一个匹配的参数就会进入,当抛出的异常没有被catch捕获时就会报错。
抛出异常的对象的传递类似函数的返回值,会拷贝生成一个临时对象,这个临时对象的生命周期会持续到对应的catch块执行结束,而且这个对象不像一般的临时变量,这个变量是不具有常形的(const,可以被普通引用接收),因为抛出的对象如果具有常性后续对于抛出对象的修改操作就没法进行了。
catch(…)可以捕获任意类型的异常,但是也没法知道捕获的是什么类型,一般不会把它放在中间,而是会将其放在最后,以防出现未知错误时及时兜底。
catch语句中的参数匹配规则并不都是要求类型完全匹配。首先,是支持非const对象向const对象转换的;再者,也是支持数组名转数组指针和函数名转函数指针的;然后,const void*指针可以接受任何类型的指针;最后同样也是最重要的,c++支持抛出派生类对象 / 指针 / 引用被基类对象 / 指针 / 引用来接受,这非常常用,在现实中的实际项目中常常采用以基类为基础继承出各个板块的派生类,再由catch块基类类型接受,再利用多态达到接受体系中各种错误的效果,这个后面会详细讲解。
在函数调用链中异常栈展开匹配原则
对于throw出的异常,首先要检查throw本身是否在try块中,在的情况下就会自上而下查找与try块对应的catch块,由匹配的就会到匹配的catch块运行。
如果throw不在当前的函数栈中的try块中或者在try块中但是没有与之匹配的catch块,就会退出当前的栈到调用这个函数的栈中看是否在try块中以及是否有与之对应的catch块。
如果到达main函数栈也依旧没有找到与之匹配的,就会报错终止程序。上述的这个沿着调用链查找匹配的catch子句的过程称之为栈展开。一般来说,最后都要加上catch(…)兜底,防止因为疏忽没有捕获导致程序直接终止。
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<string>using namespace std;void test()
{throw string();
}int main()
{try{test();}catch(...)//接受任何类型{}
}
在throw出异常后,程序就不会在按照正常的流程去跑了,先是按照栈展开(调试中栈展开这个过程是看不到的,编译器在throw后会直接跳转到匹配的catch块,或者没有匹配的直接报错,不会一个栈一个栈地退,这是编译器优化的结果)进行回退,回退时会消除没有匹配的函数栈帧,到达catch块处理完后会继续执行catch子句后面的语句。
异常的重新抛出
有可能单个的catch不能完全处理一个异常,在进行一些校正处理以后,希望再交给更外层的调用链函数来处理,catch则可以通过重新抛出将异常传递给更上层的函数进行处理。
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<string>using namespace std;void test_2()
{string str("test_2 error");throw str;
}void test_1()
{int* a = new int(1);test_2();cout << "Deletion successful" << endl;delete a;
}int main()
{try{test_1();}catch (string x){cout << x << endl;}return 0;
}
像上面这种情况,如果自己向堆上动态申请了内存,而且想要在main函数中统一处理异常,此时就会因为throw出的异常导致跳过了堆的内存释放,这样就会导致内存泄漏,
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<string>using namespace std;void test_2()
{string str("test_2 error");throw str;
}void test_1()
{int* a = new int(1);try{test_2();}catch(string x){cout << "Deletion successful" << endl;delete a;throw;}cout << "Deletion successful" << endl;delete a;
}int main()
{try{test_1();}catch (string x){cout << x << endl;}return 0;
}
这时我们就可以先捕获一下异常,在catch块中释放掉申请的内存,然后重新抛出异常给后面的catch块接受统一处理。重新抛出的方法也很简单,直接在catch块中写throw; 就表示将捕获到的异常再次抛出。
重新抛出的方式可以解决一些简单场景的内存释放,但对于多次内存开辟加多次函数调用,因为内存开辟也是会开辟失败抛异常的,所以会要求捕获多种类型,就会比较麻烦,需要搭配智能指针来使用。
异常规范
throw(类型)
1.异常规格说明的目的是为了让函数使用者知道该函数可能抛出的异常有哪些。 可以在函数的后面接throw(类型),列出这个函数可能抛掷的所有异常类型。
2. 函数的后面接throw(),表示函数不抛异常。
3. 若无异常接口声明,则此函数可以抛掷任何类型的异常。
void test_1() throw()//不会抛异常
{//...
}void test_2() throw(int, double)//只会抛int和double类型的异常
{//...
}void test_3() //可以抛任何类型的异常
{//...
}
这套体系看起来严格规定了函数异常抛出的类型,但是即使不遵守,函数也不会报错,这是c++为了兼容旧代码导致的结果。所以这就象是一种口头承诺了,防君子而不防小人。其实,从实际使用的角度上来说,这样的设计也是不好的,每次写函数表明可能会抛出的异常类型会非常麻烦,而且实际开发时就连开发者自己也不会清楚自己这个函数会抛出多少种异常,也许我写的这个函数调用的接口是项目组中的其他人所写的,也有可能未来还要对项目的功能进行扩展调用更多的接口,这些都是不确定因素,全部写明是非常困难且麻烦的。而且throw()是在运行时生成隐式try-catch代码块,动态检查异常类型是否规范,会有一定的性能开销。这种设计本意希望帮助调用者预判异常类型,简化错误处理逻辑,但在实际开发中没什么用处,而且在c++的新版本中也已经逐步被废弃,throw仅作为提示作用兼容老版本代码,运行时不会强制验证,所以不推荐使用。
noexcept
void test_1() noexcept//不会抛异常
{//...
}void test_2() //会抛各种类型的异常
{//...
}
noexcept是c++11新增的关键字,用来替代throw()用的。函数后面加noexcept表示这个函数不会抛出异常,编译器会严格检查声明函数是否抛出了异常。相较于throw()的运行时的动态检查 ,noexcept是在编译时就确定的静态检查,编译器还进一步优化了noexcept的异常抛出,noexcept的异常抛出不会进行栈展开一个个释放函数栈帧,而是直接报错,所以noexcept比throw的效率高很多。noexcept声明过的函数表示不会抛出异常,编译器也会对此做出优化,进一步提升函数效率。
综上,实际写代码时如果遇到确定不会抛异常的函数,加一个noexcept优化一下就行了,throw因为各种历史包袱,现在已经被废弃,没什么人用了。
成熟的异常体系
虽然c++在语法上支持我们抛出任意类型的异常,但是在成熟的项目开发中是有一套成熟的异常体系的,一个好的异常体系可以大大提高项目开发效率,减少项目维护成本。
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<string>using namespace std;class My_Exception
{
protected:int err_id;string err_msg;
public:My_Exception(const string& errmsg, int errid):err_id(errid),err_msg(errmsg){}virtual string what() const{return err_msg;}
};class A : public My_Exception
{string A_err_mesg;
public:A(int x, string y, string z):My_Exception(y, x),A_err_mesg(z){}virtual string what() const{string str("A : ");str += err_msg;str += ",";str += A_err_mesg;return str;}
};class B : public My_Exception
{string B_err_mesg;
public:B(int x, string y, string z) :My_Exception(y, x),B_err_mesg(z){}virtual string what() const{string str("B : ");str += err_msg;str += ",";str += B_err_mesg;return str;}
};void test_A()
{A x(1, "错误描述", "A组的错误信息");throw x;
}void test_B()
{B x(2, "错误描述", "B组的错误信息");throw x;
}int main()
{try{test_A();}catch (My_Exception& x){cout << x.what() << endl;}try{test_B();}catch (My_Exception& x){cout << x.what() << endl;}return 0;
}
上面是一个简单的一场体系,实际的项目中肯定会更成熟以及复杂。但通过上面的例子可以看出一场体系的关键所在。即定义一个类专门用来记录最基本的异常信息,这里就给出了错误id和错误描述,错误id可以表示哪个模块发生了错误,这个我们可以事先定义好,比如数据库模块的id为001,网络模块的id为002,等等;错误描述可以是一些最基本的错误描述,比如权限不足,数据不存在,等等一些通用的错误描述。这些异常信息必须是所有异常都会有的,然后再由这个类衍生出各种派生类,这些派生类记录实际项目中各个模块的错误信息,他们可以在继承父类的最基本的错误信息的基础之上,再定义一些自己独有的错误信息,比如数据库模块的错误就可以给出具体的sql语句,网络模块错误就给出错误码等等,这些东西的自由度很高,我们可以给出很详细的信息极大的方便我们在代码错误之后的错误查找。然后就是这些错误的捕获,我们之所以使用派生类来作为记录异常的类就是因为c++允许用catch子句用基类的对象 / 指针 / 引用接受派生类的对象 / 指针 / 引用,所以我们就可以定义一个what虚函数,体系中每个类的what虚函数都返回自己整理好的独特的错误信息,这样通过多态达到以一种类型接受整个异常体系中所有异常类的效果,如果不使用这套思路,面对大型项目的多个模块,光写catch子句就得写累死,所以这套体系还是强烈推荐的。
c++自己的异常体系
c++有自己的异常体系,也是通过父子类来完成的。
这些错误我们在日常写代码时肯定都遇到过一些。
我们可以用try块包裹住可能会出现错误的位置,使用exception类型就能捕获这些错误发生时会抛出的异常,当然,我们也能主动抛出这些异常,
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<string>using namespace std;int main()
{try{throw bad_alloc();//new会抛出的异常}catch (const exception& e){cout << e.what() << endl;}return 0;
}
c++虽然有自己的一套异常体系,但是不够好用,很多公司都会有自己的一套异常体系。
异常的优缺点
优点
(1)异常对象定义好了,相比错误码的方式可以清晰准确的展示出错误的各种信息,甚至可以包含堆栈调用的信息,这样可以帮助更好的定位程序的bug。
(2)返回错误码的传统方式有个很大的问题就是,在函数调用链中,深层的函数返回了错误,那么我们得层层返回错误,最外层才能拿到错误,具体看下面的详细解释。
(3)很多的第三方库都包含异常,比如boost、gtest、gmock等等常用的库,那么我们使用它们也需要使用异常。
(4)部分函数使用异常更好处理,比如构造函数没有返回值,不方便使用错误码方式处理。比如T& operator这样的函数,如果pos越界了只能使用异常或者终止程序处理,没办法通过返回值表示错误。
缺点
(1) 异常会导致程序的执行流乱跳,并且非常的混乱,并且是运行时出错抛异常就会乱跳。这会导致我们跟踪调试时以及分析程序时,比较困难,有时候打断点都可能断不住。
(2)异常会有一些性能的开销。当然在现代硬件速度很快的情况下,这个影响基本忽略不计。
(3)C++没有垃圾回收机制,资源需要自己管理。有了异常非常容易导致内存泄漏、死锁等异常安全问题。这个需要使用RAII来处理资源的管理问题。学习成本较高。
(4)C++标准库的异常体系定义得不好,导致大家各自定义各自的异常体系,非常的混乱。
(5)异常尽量规范使用,否则后果不堪设想,随意抛异常,外层捕获的用户苦不堪言。所以异常规范有两点:一、抛出异常类型都继承自一个基类。二、函数是否抛异常、抛什么异常,都使用 func() throw();的方式规范化。
总的来说,异常还是利大于弊,日常代码中可以使用来对代码中的各种错误进行检查。c++的异常也被后来的一些面向对象语言所借鉴。
异常安全
(1)构造函数完成对象的构造和初始化,最好不要在构造函数中抛出异常,否则可能导致对象不完整或没有完全初始化。
(2)析构函数主要完成资源的清理,最好不要在析构函数内抛出异常,否则可能导致资源泄漏(内存泄漏、句柄未关闭等)
(3)C++中异常经常会导致资源泄漏的问题,比如在new和delete中抛出了异常,导致内存泄漏,在lock和unlock之间抛出了异常导致死锁,C++经常使用RAII来解决以上问题。
相关文章:
【c++】异常详解
目录 C语言处理错误的局限性异常的定义异常的具体使用细则异常的抛出与捕获在函数调用链中异常栈展开匹配原则异常的重新抛出异常规范throw(类型)noexcept 成熟的异常体系c自己的异常体系异常的优缺点优点缺点 异常安全 C语言处理错误的局限性 C语言处理错误常常会用到assert和…...
从模型加密到授权交付,CodeMeter赋能3D打印商业化全流程
引言 在数字化制造快速演进的当下,3D 打印(增材制造)作为具备高度灵活性与创新潜力的制造方式,正重塑备件供应链与产品生命周期管理。然而,随着应用场景不断扩展,企业面临的知识产权保护、数字资产商业化与…...
ESP32开发之freeRTOS的事件组
什么是事件组事件组的应用场景事件组的API函数事件组应用举例总结什么是事件组 概念:事件组就是一个整数,高8位给内核使用,其他位用来表示事件。在ESP32的IDF freeRTOS中,这个整数是32位的,低24位用来供事件组使用。 举一个生活中的例子: 你在等快递,有三个包裹来自不…...
K8S中构建双架构镜像-从零到成功
背景介绍 公司一个客户的项目使用的全信创的环境,服务器采用arm64的机器,而我们的应用全部是amd64的,于是需要对现在公司流水线进行arm64版本的同步镜像生成。本文介绍从最开始到最终生成双架构的全部过程,以及其中使用的相关配置…...
腾讯怎样基于DeepSeek搭建企业应用?怎样私有化部署满血版DS?直播:腾讯云X DeepSeek!
2025新春,DeepSeek横空出世,震撼全球! 通过算法优化,DeepSeek将训练与推理成本降低至国际同类模型的1/10,极大的降低了AI应用开发的门槛。 可以预见,2025年,是AI应用落地爆发之年! ✔…...
【论信息系统项目的质量管理】
论信息系统项目的质量管理 前言一、抓好质量管理规划工作,为质量管理和确认提供指南和方向。二、做好管理质量相关工作,促进质量过程改进。三、抓好控制质量,确保实现质量目标四、综合协调质量与成本、进度、范围的关系总结 前言 为解决日常出…...
SpringAI框架中的RAG模块详解及应用示例
SpringAI框架中的RAG模块详解及应用示例 RAG(Retrieval-Augmented Generation)可以通过检索知识库,克服大模型训练完成后参数冻结的局限性,携带知识让大模型根据知识进行回答。SpringAI框架提供了模块化的API来支持RAG࿰…...
图像增强技术
一、目的 通过本实验加深对数字图像增强操作的理解,熟悉MATLAB中的有关函数;了解直方图均衡化和卷积滤波的原理;熟悉低通和高通滤波模板的构造方法。 二、实验内容与设计思想 1、观察实验结果可看出, 原图像 I的对比度较低&…...
【Java学习笔记】多态参数
多态参数 应用:方法定义的形参类型为父类类型,实参允许为子类类型 // 父类 package polyparemeter;public class employee {private String name;private double salary;//构造器public employee(){}public employee(String name, double salary) {thi…...
计算机网络核心技术解析:从基础架构到应用实践
计算机网络作为现代信息社会的基石,承载着全球数据交换与资源共享的核心功能。本文将从网络基础架构、核心协议、分层模型到实际应用场景,全面解析计算机网络的核心技术,并结合行业最新趋势,为读者构建系统的知识体系。 一、计算机…...
LiveData:Android响应式编程的核心利器
LiveData是一种可观察的数据持有类,用于在Android应用中实现数据的响应式编程。它具有以下特点和作用: 特点 生命周期感知:LiveData能够感知与其关联的组件(如Activity、Fragment)的生命周期状态。只有当组件处于活跃状态(如Activity处于RESUMED状态)时,LiveData才会将…...
【LeeCode】1.两数之和
文章目录 1. 暴力求解2. 哈希表具体过程1. nums [2, 7, 11, 15],target 9:2. nums [11, 15, 2, 7], target 9 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数ÿ…...
继承关系下创建对象的具体流程
public class Person {int x initX(); // 显式初始化:调用方法 initX()public Person() {System.out.println("Parent 构造器执行, x " x);}int initX() {System.out.println("initX() 被调用了");return 100;} }public class Child extends…...
基于世界土壤数据库(HWSD)的中国土壤数据集(v1.1)(2009)
时间分辨率:年共享方式:开放获取数据大小:156.47 MB数据时间范围:2009元数据更新时间:2020-03-26 数据集摘要 数据来源于联合国粮农组织(FAO)和维也纳国际应用系统研究所(IIASA)所构建的世界土…...
mac M2能安装的虚拟机和linux系统系统
目前网上的资料大多错误,能支持M2的很少。 推荐安装的改造过的centos7也无法进行yum操作,建议安装centos8 VMware Fusion下载地址: https://pan.baidu.com/s/14v3Dy83nuLr2xOy_qf0Jvw 提取码: jri4 centos8下载地址: https://…...
212. 单词搜索 II【 力扣(LeetCode) 】
文章目录 零、原题链接一、题目描述二、测试用例三、解题思路四、参考代码 零、原题链接 212. 单词搜索 II 一、题目描述 给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words, 返回所有二维网格上的单词 。 单词必须按照字母…...
【软考-高级】【信息系统项目管理师】论文写作注意事项及2014年至2024年历年论文题目汇总
论文写作注意事项 要求 字数要求:2500字以内(2024年超过2500字,在线答题系统无法输入)时长要求:2小时(大多数人不够用)内容要求: 必须响应子标题,如子标题要求写如何优…...
MySQL数据库表的约束
目录 1.null属性 2.默认值约束(default) 3.comment 4.zerofill 5.主键(primary key) 6.自增长(auto_increment) 7.唯一键(unique) 编辑 8.外键 约束是为了安全插入数据&a…...
硅基计划2.0 学习总结 壹 Java初阶
一、初见Java (1)Java简介 首先不得不承认Java是一门优秀的程序设计语言 其系列的计算机软件和跨平台体系包括国内的生态链完善是C/C语言难以弥补的 (2)Java SE 全称Java Standard Edition,是Java体系的基础 &am…...
逆向破解:x64dbg
文章目录 一、CPU窗口1、反汇编窗口2、寄存器窗口3、栈地址窗口4、十六进制数据窗口5、堆栈参数解析窗口 二、常用快捷键三、字符串检索功能四、调试功能1、上一步 一、CPU窗口 1、反汇编窗口 2、寄存器窗口 寄存器窗口用于显示和解释当前线程环境下CPU寄存器的各种状态值和内…...
从MCU到SoC的开发思维转变
目录 1、硬件设计 2、软件开发 3、调试与测试 4、电源管理 微控制器单元(MCU)和系统级芯片(SoC)是嵌入式开发中最常见的两种处理器类型。MCU以其简单、低功耗的特点,广泛应用于特定控制任务;而SoC凭借强…...
3DGS-to-PC:3DGS模型一键丝滑转 点云 or Mesh 【Ubuntu 20.04】【2025最新版!!】
一、引言 3D高斯泼溅(3DGS)是一种新兴的三维场景表示方法,可以生成高质量的场景重建结果。然而,要查看这些重建场景,需要特殊的高斯渲染器。大多数3D处理软件并不兼容3D高斯分布模型,但它们通常都兼容点云文件。 3DGS-to-PC项目提…...
互联网大厂Java求职面试:优惠券服务架构设计与AI增强实践-3
互联网大厂Java求职面试:优惠券服务架构设计与AI增强实践-3 场景背景 面试场景设定在一家大型互联网公司,面试官为拥有10年以上经验的技术总监,专注于高并发、高可用系统的架构设计。候选人郑薪苦是一名技术潜力十足的程序员,擅…...
ABP-Book Store Application中文讲解 - 前期准备 - Part 3:Acme.BookStore项目模块详解
ABP-Book Store Application中文讲解-汇总-CSDN博客 本文通过对Acme.BookStore项目各模块的详解,让大家知道每个project用来干什么的,他们之间的引用关系是什么,同时知道怎样添加新的功能模块。 Acme.Bookstore 是主要 ABP Studio 模块的主…...
智慧城市综合运营管理系统Axure原型
这款Axure原型的设计理念紧紧围绕城市管理者的需求展开。它旨在打破传统城市管理中信息孤岛的局面,通过统一标准接入各类业务系统,实现城市运营管理信息资源的全面整合与共享。以城市管理者为中心,为其提供一个直观、便捷、高效的协同服务平台…...
Java中进阶并发编程
第一章、并发编程的挑战 并发和并行:指多线程或多进程 线程的本质:操作系统能够进行运算调度的最小单位,是进程(Process)中的实际工作单元 进程的本质:操作系统进行资源分配和调度的基本单位,…...
cursor 出现问题 为客户解决问题
文档出自:https://www.kdocs.cn/l/cp5GpLHAWc0p...
【氮化镓】GaN在不同电子能量损失的SHI辐射下的损伤
该文的主要发现和结论如下: GaN的再结晶特性 :GaN在离子撞击区域具有较高的再结晶倾向,这导致其形成永久损伤的阈值较高。在所有研究的电子能量损失 regime 下,GaN都表现出这种倾向,但在电子能量损失增加时,其效率会降低,尤其是在材料发生解离并形成N₂气泡时。 能量损失…...
用drawdb.app可视化创建mysql关系表
平时自己建表,没有可视化图形参考 为了便于理解,用drwadb画mysql关系表 drawDB | Online database diagram editor and SQL generator...
模型上下文协议(MCP):AI的“万能插座”
~犬📰余~ “我欲贱而贵,愚而智,贫而富,可乎? 曰:其唯学乎” 一、MCP解决什么问题? \quad 在过去的几年中,AI大模型快速发展,从横空出世的GPT到“AI界拼多多”DeepSeek&am…...
初识 Pandas:Python 数据分析的利器
在数据分析、数据清洗和可视化等领域,Python 无疑是最受欢迎的语言之一,而在 Python 的数据处理生态中,Pandas 是最核心、最基础的库之一。如果你接触数据分析、机器学习、金融建模,或者只是想处理一些 Excel 表格,那么…...
Python教程(四)参数提取pymysql
Python(四) 本系列其他教程: Python教程(二):函数、异常、模块&包、文件读取、常用模块 Python教程(三):类&对象、闭包、装饰器、类型注解 Python教程(三):类&对象、闭包、装饰器、类型注解、…...
Halcon案例(一):C#联合Halcon识别路由器上的散热孔
本案例分3部分 识别效果,分别显示识别前后识别后;代码展示,分别是Halcon源码和Halcon转为C#的代码代码解释(解释在源码中) 原图如下: 处理后的图像: Halcon源码: *读取一张图像 read_image (Image, progres)*获取图像大小 get_image_size (Image, Width, Height)*关…...
SC5061串口设备联网服务器,4路RS-232,4路422/485串行接口
串口设备联网服务器,简称串口服务器。能够将RS-232/485/422串口设备联入TCP/IP网络,实现RS-232/485/422串口与TCP/IP网络接口的数据双向传输,使得串口设备能够具备联网功能,根据串口数量的不同,可以分为单串口、两串口…...
谈AI/OT 的融合
过去的十几年间,工业界讨论最多的话题之一就是IT/OT 融合,现在,我们不仅要实现IT/OT 的融合,更要面向AI/OT 的融合。看起来不太靠谱,却留给我们无限的想象空间。OT 领域的专家们不要再当“九斤老太”,指责这…...
RAGFlow 初步尝试 (01)
1. 起因, 目的: 简单尝试一下。 2. 先看效果 3. 过程: 目的: 研究 RAG 的实现过程。 实用目的: 对于一本电子书, pdf,我在读书的时候,可以问一写些问题。对一个 github 项目,可以迅速理解文件的关系。…...
Linux 服务器用 SSH 拉取多个 Git 工程
在一台 Linux 服务器上用 SSH 拉取两个 Git 工程,而这两个工程对应的是 不同的 Git 账号(SSH Key),做法: 使用 SSH Config 配置多个 Git 账号 场景假设: 工程 A 的仓库地址:gitgithub.com:com…...
测试文章标题01
模型上下文协议(Model Context Protocol, MCP)深度解析 一、MCP的核心概念 模型上下文协议(Model Context Protocol, MCP)是一种用于规范机器学习模型与外部环境交互的标准化框架。其核心目标是通过定义统一的接口和数据格式&am…...
如何禁止chrome自动更新
百度了一下 下面这个方法实测有效 目录 1、WINR 输入 services.msc 2、在Services弹窗中找到下面两个service并disable 3、验证是否禁止更新成功: 1、WINR 输入 services.msc 2、在Services弹窗中找到下面两个service并disable GoogleUpdater InternalService…...
【C++重载操作符与转换】构造函数和复制控制
目录 一、构造函数:对象的初始化引擎 1.1 构造函数的定义与分类 1.2 初始化列表:高效且安全的初始化方式 1.3 显式构造函数与类型安全 二、复制控制:管理对象的生命周期 2.1 复制构造函数:深拷贝的核心 2.2 赋值运算符重载…...
CATIA高效工作指南——常规配置篇(二)
一、结构树(Specification Tree)操作技巧精讲 结构树是CATIA设计中记录模型历史与逻辑关系的核心模块,其高效管理直接影响设计效率。本节从基础操作到高级技巧进行系统梳理。 1.1 结构树激活与移动 激活方式: 白线…...
神经生物学+图论双buff,揭示大脑语言系统的拓扑结构
摘要 近年来,神经影像数据分析的进展促进了大脑网络整合中适应性变化的表征。本研究提出了一种融合知识驱动与数据驱动的独特方法,为更精确地理解这些变化提供了新思路。通过运用图网络分析,并结合特定领域脑网络系统的现有神经生物学知识&am…...
Kotlin 懒初始化值
Kotlin 懒初始化值:深入理解 lateinit 与 by lazy 在 Kotlin 开发中,懒初始化(Lazy Initialization) 是一种常见的优化技巧,它允许我们将对象的初始化延迟到真正需要使用时再执行。Kotlin 提供了两种核心机制来实现懒…...
高速系统设计实例设计分析
在上几章的内容中,我们从纯粹高速信号的理论分析,到 Cadence 工具的具体使用都做了详细的讲解和介绍。相信读者通过前面章节的学习,已经对高速系统的设计理念及 Cadence 相应的设计流程和工具有了一个基本的认识。但是,对于高速电…...
数据结构与算法学习-JavaScript的Array.prototype.reduce()方法
一、语法 array.reduce(callbackfn, initialValue);callbackfn (accumulator, currentValue, currentIndex, array) > {// 回调逻辑 } callbackFn 为数组中每个元素执行的函数。 其返回值将作为下一次调用 callbackFn 时的 accumulator 参数。对于最后一次调用,…...
[Java][Leetcode simple] 189. 轮转数组
借助辅助数组 借助一个辅助数组tmp保存后面k个元素然后逆序循环,使用数组前面n-k个元素覆盖最后到后面最后把前k个元素从tmp中拿回来public void rotate(int[] nums, int k) {int len nums.length;k k % len;int[] Ra new int[len];int cnt 0;for (int i len-k…...
Hadoop 的代理用户(Proxy User) 功能解释
在$HADOOP_HOME/etc/hadoop下的core-site.xml 配置里,可以新增hadoop集群的代理用户。 在集成配置中,会经常用到。它属于 Hadoop 安全机制的一部分。 以下是对该配置效果的详细说明及示例: 配置效果 <!-- 允许用户 hadoop 从主机 hadoop…...
day06_java中的流程控制语句
流程控制语句 Java提供了一些流程控制语句,来控制程序的执行流程 顺序结构 任何编程语言中最常见的程序结构就是顺序结构顺序结构就是程序从上到下逐行地执行,中间没有任何判断和跳转如果main方法的多行代码之间没有任何流程控制,则程序总是…...
机器学习实战:归一化与标准化的选择指南
在机器学习实战中——是否需要归一化(Normalization)或标准化(Standardization),取决于所使用的模型类型。 ✅ LightGBM / XGBoost 是否需要归一化或标准化? 不需要。 🔧 原因: L…...
【内蒙古】《内蒙古自治区本级政务信息化建设项目预算支出标准(试行)》(内财预〔2024〕1449号)-费用标准解读系列
内蒙古自治区政务服务与数据管理局在2024年11月29日发布了《内蒙古自治区本级政务信息化建设项目预算支出标准(试行)》(内财预〔2024〕1449号)。该文件适用于自治区本级各部门、单位非涉密政务信息化建设项目(以下简称建设项目)经费的预算编制、审核。下…...