C++ ---智能指针详解
文章目录
- 前言
- 一、 为什么需要智能指针?
- 二、内存泄漏
- 2.1 什么是内存泄露?危害是什么?
- 2.2 内存泄露的分类
- 2.3 如何避免内存泄露
- 三、智能指针的使用及原理
- 3.1 RAII
- 3.2 智能指针的原理
- 3.3 std::autoptr
- 3.4 std::unique_ptr
- 3.5 std::shared_ptr
- std::shared_ptr的循环引用问题
- 3.6 std::weak_ptr
- 四、定制删除器
- 五、完整代码
- 六、C+11和boost中智能指针的关系
- 总结
前言
正文开始
一、 为什么需要智能指针?
首先我们来分析下面的程序有没有什么关于内存方面的问题呢?
注意:分析func函数中的问题
int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}
void Func()
{int* p1 = new int;// 1、如果p1这里new 抛异常会如何?int* p2 = new int;// 2、如果p2这里new 抛异常会如何?cout << div() << endl;// 3、如果div调用这里又会抛异常会如何?delete p1;delete p2;
}
int main()
{try{Func();}catch (exception& e){cout << e.what() << endl;}return 0;
}
问题分析:上面的问题分析出来我们发现有什么问题?
- 在这里抛异常会在main函数中捕捉,不会导致问题.
- 在这里抛异常会在main函数中捕捉,但是new p1的空间没有释放,导致内存泄露!
- 调用div函数后抛异常会在main函数中捕捉,但是new p1和p2的空间没有释放,导致内存泄露!
二、内存泄漏
2.1 什么是内存泄露?危害是什么?
内存泄漏: 内存泄露指因为疏忽或错误造成程序未能释放已经不再使用的内存情况.内存泄露并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费.
内存泄露的危害: 长期运行的程序出现内存泄露,影响很大,如操作系统、后台服务等等,出现内存泄露会导致响应越来越慢,最终卡死.
int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}
void func()
{// 1.内存申请了忘记释放int* p1 = (int*)malloc(sizeof(int));int* p2 = new int;// 2.异常安全问题int* p3 = new int[10];div(); // 这里div函数抛异常导致delete[] p3 未执行,p3没有被释放delete[] p3;
}
2.2 内存泄露的分类
C/C++程序中一般关心两种方面的内存泄露:
- 堆内存泄露(Heap Leak)
堆内存是指程序执行中依据须要分配通过malloc/calloc/realloc/new等从堆中分配的一块内存,用完之后必须通过调用相应的free或者delete删掉.假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak. - 系统资源泄露
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定.
2.3 如何避免内存泄露
- 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放.ps:这个理想状态.但是如果碰上异常时,就注意释放了,还是可能会出问题.需要下一条智能指针来管理才有保证.
- 采用PAII思想或者智能指针来管理资源.
- 有些公司内部规范使用内部实现的私有内存管理库.这套库自带内存泄露检测的功能选项.
总结:内存泄漏非常常见,解决方案分为两种: 1.事前预防型.如智能指针等. 2. 事后查错型.如泄露检测工具等.
三、智能指针的使用及原理
3.1 RAII
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文字句柄、网络连接、互斥量等等)简单技术.
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,**最后在对象析构的时候释放资源.**借此,实际上把管理一份资源的责任托管给一个对象.
这种做法有两大好处:
- 不需要显式地释放资源.
- 采用这种方式,对象所需的资源在其生命周期内始终保持有效.
//使用RAII的思想设计的SmartPtr类
namespace hulu
{template<class T>class SmartPtr{public:SmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){cout << "delete[]" << _ptr << endl;delete[] _ptr;}private:T* _ptr;};
}
double div()
{double a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}
void Func()
{hulu::SmartPtr<int> sp1(new int[10]);hulu::SmartPtr<int> sp2(new int[10]);hulu::SmartPtr<int> sp3(new int[10]);hulu::SmartPtr<int> sp4(new int[10]);div();}
int main()
{try {Func();}catch (const exception& e){cout << e.what() << endl;}return 0;
}
不抛出异常的情况
抛出异常的情况
3.2 智能指针的原理
上述的SmartPtr还不能称其为智能指针,因为他还不具有指针的行为,指针可以解引用,也可以通过->去访问所指空间中的内容,因此: auto_ptr模板类中还需要将、->重载下,才可让其像指针一样去使用.*
namespace hulu
{template<class T>class SmartPtr{public:SmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){cout << "delete[]" << _ptr << endl;//delete[] _ptr;delete _ptr;}//像指针一样T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};
}
总结智能指针的原理:
- RAII特性
- 重载operator*和operator->,具有像指针一样的行为!
3.3 std::autoptr
auto_ptr的文档介绍
C++98版本的库中就提供了auto_ptr的智能指针.下面演示的auto_ptr的使用及问题.
auto_ptr的实现原理:管理权转移的思想,下面模拟实现了一份hulu::auto_ptr来了解的它的原理.
namespace hulu
{template<class T>class auto_ptr{public:auto_ptr() {}auto_ptr(T* ptr):_ptr(ptr){ptr = nullptr;}auto_ptr(auto_ptr<T>& sp):_ptr(sp._ptr){sp._ptr = nullptr;}auto_ptr<T>& operator=(auto_ptr<T>& sp){//检测是不是自己给自己赋值if (this != &sp){//释放当前对象的资源if (_ptr)delete _ptr;//转移sp中的资源到当前对象_ptr = sp._ptr;sp._ptr = nullptr;}return *this;}~auto_ptr(){if (_ptr){cout << "delete[]" << _ptr << endl;delete _ptr;_ptr = nullptr;}}//像指针一样T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};
}
//C++98 auto_ptr 管理权转移,被拷贝的对象悬空
int main()
{//std::auto_ptr<int> sp1(new int);//std::auto_ptr<int> sp2 = sp1;hulu::auto_ptr<int> sp1(new int);hulu::auto_ptr<int> sp2 = sp1;hulu::auto_ptr<int> sp3;sp3 = sp1;// sp1悬空//*sp1 = 10;*sp2 = 20;return 0;
}
3.4 std::unique_ptr
C++11中开始提供更靠谱的unique_ptr
unique_ptr的使用文档
unqiue_ptr的实现原理:简单粗暴的防拷贝,下面简单模拟实现了一份unique_ptr来了解它的原理.
namespace hulu{template<class T>class unique_ptr{public:unique_ptr(T* ptr):_ptr(ptr){}~unique_ptr(){if (_ptr){cout << "delete[]" << _ptr << endl;delete _ptr;_ptr = nullptr;}}//像指针一样T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:unique_ptr(unique_ptr<T>& sp)= delete;unique_ptr<T>& operator=(const unique_ptr<T>& sp)= delete;private:T* _ptr;};
}
3.5 std::shared_ptr
C++11中开始提供更靠谱的并且支持拷贝的shared_ptr
share_ptr的文档介绍
**shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源.**例如:上课开始前,最后一个进入教室的学生需要把门锁着.
- shared_ptr在其内部,给每个资源都维护了一份计数,用来记录该份资源被几个对象共享.
- 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一
- 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源.
- 如果不是0就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了.
// 引用计数支持多个拷贝管理同一个资源,最后一个析构对象释放资源
namespace hulu
{template<class T>class shared_ptr{public:shared_ptr(T* ptr):_ptr(ptr),_pCount(new int(1)){}~shared_ptr(){Release();}shared_ptr(const shared_ptr<T>& sp):_ptr(sp._ptr),_pCount(sp._pCount){(*_pCount)++;}void Release(){if (--(*_pCount) == 0 && _ptr){cout << "delete[]" << _ptr << endl;delete _ptr;delete _pCount;_pCount = nullptr;_ptr = nullptr;}}//sp1 = sp3shared_ptr<T>& operator=(shared_ptr<T>& sp){// 检测是否自身赋值//if (this != &sp)if (_ptr == sp._ptr) // 防止sp1 == sp2{Release();_ptr = sp._ptr;_pCount = sp._pCount;(*_pCount)++;}return *this;}//像指针一样T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;int* _pCount;};
}
std::shared_ptr的循环引用问题
struct ListNode
{ListNode* _next = nullptr;ListNode* _prev = nullptr;int _val = 0;~ListNode(){cout << "~ListNode()" << endl;}
};int main()
{std::shared_ptr<ListNode> p1(new ListNode);std::shared_ptr<ListNode> p2(new ListNode);p1->_next = p2;p2->_prev = p1;return 0;
}
进行编译后报错,显示类型不匹配,这是因为在"p1->_next = p2;"中,p2是std::shared_ptr类型,而p1->_next 的类型我们从结构体中可以看出是ListNode*,所以编译就会报错.
那么我们如何解决如上问题呢?
因为我们要使用智能指针,所以将结构体中的类型进行更改为
struct ListNode
{std::shared_ptr<ListNode> _next = nullptr;std::shared_ptr<ListNode> _prev = nullptr;int _val = 0;~ListNode(){cout << "~ListNode()" << endl;}
};
编译后我们发现
p1,p2应该要进行销毁,去调用自己的析构函数,但是我们发现实际上却没有调用,所以一定造成了内存泄露,那么这是为什么呢?
引入循环引用问题:
画图分析如下:
接下来需要我们引入新的智能指针(std::weak_ptr)
这个weak_ptr可以接受shared_ptr进行传参,此时这个weak_ptr只负责连接,不负责去进行引用计数,这样就很好的解决了循环引用的问题!
struct ListNode
{std::weak_ptr<ListNode> _next;std::weak_ptr<ListNode> _prev;int _val = 0;~ListNode(){cout << "~ListNode()" << endl;}
};int main()
{std::shared_ptr<ListNode> p1(new ListNode);std::shared_ptr<ListNode> p2(new ListNode);p1->_next = p2;p2->_prev = p1;return 0;
}
3.6 std::weak_ptr
template<class T>class weak_ptr{public:weak_ptr():_ptr(nullptr){}weak_ptr(const shared_ptr<T>& sp):_ptr(sp.Get()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){if (_ptr != sp.Get()){_ptr = sp.Get();}return *this;}private:T* _ptr;};struct ListNode
{hulu::weak_ptr<ListNode> _next;hulu::weak_ptr<ListNode> _prev;int _val = 0;~ListNode(){cout << "~ListNode()" << endl;}
};int main()
{hulu::shared_ptr<ListNode> p1(new ListNode);hulu::shared_ptr<ListNode> p2(new ListNode);p1->_next = p2;p2->_prev = p1;return 0;
}
weak_ptr不参与指向资源的释放管理!
四、定制删除器
如果不是new出来的对象如何通过智能指针管理呢?其实shared_ptr设计了一个删除器来解决这个问题!
class Date
{
public:~Date(){cout << "~Date()" << endl;}
private:int _year = 0;int _month = 1;int _day = 1;
};// unique_ptr/shared_ptr 默认释放资源用的delete
int main()
{std::unique_ptr<Date> up1(new Date);std::unique_ptr<Date> up2(new Date[10]);std::unique_ptr<Date> up3((Date*)malloc(sizeof(Date)*10));return 0;
}
如何匹配申请方式去释放呢?
class Date
{
public:~Date(){cout << "~Date()" << endl;}
private:int _year = 0;int _month = 1;int _day = 1;
};// unique_ptr/shared_ptr 默认释放资源用的deletetemplate<class T>
struct DeleteArray
{void operator()(T* ptr){cout << "delete[] " <<ptr<< endl;delete[] ptr;}
};template<class T>
struct Free
{void operator()(T* ptr){cout << "free " << ptr << endl;free(ptr);}
};int main()
{std::unique_ptr<Date> up1(new Date);std::unique_ptr<Date,DeleteArray<Date>> up2(new Date[10]);std::unique_ptr<Date,Free<Date>> up3((Date*)malloc(sizeof(Date)*10));return 0;
}
五、完整代码
#pragma oncenamespace hulu
{template<class T>class SmartPtr{public:SmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){cout << "delete[]" << _ptr << endl;//delete[] _ptr;delete _ptr;_ptr = nullptr;}//像指针一样T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};template<class T>class auto_ptr{public:auto_ptr() {}auto_ptr(T* ptr):_ptr(ptr){ptr = nullptr;}auto_ptr(auto_ptr<T>& sp):_ptr(sp._ptr){sp._ptr = nullptr;}auto_ptr<T>& operator=(auto_ptr<T>& sp){//检测是不是自己给自己赋值if (this != &sp){//释放当前对象的资源if (_ptr)delete _ptr;//转移sp中的资源到当前对象_ptr = sp._ptr;sp._ptr = nullptr;}return *this;}~auto_ptr(){if (_ptr){cout << "delete[]" << _ptr << endl;delete _ptr;_ptr = nullptr;}}//像指针一样T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};template<class T>struct default_delete{void operator()(T* ptr){cout << "delete" << ptr << endl;delete ptr;}};template<class T,class D = default_delete<T>>class unique_ptr{public:unique_ptr(T* ptr):_ptr(ptr){}~unique_ptr(){if (_ptr){/*cout << "delete[]" << _ptr << endl;delete _ptr;*/D del;del(_ptr);_ptr = nullptr;}}//像指针一样T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:unique_ptr(unique_ptr<T>& sp)= delete;unique_ptr<T>& operator=(const unique_ptr<T>& sp)= delete;private:T* _ptr;};template<class T, class D = default_delete<T>>class shared_ptr{public:shared_ptr(T* ptr):_ptr(ptr),_pCount(new int(1)){}~shared_ptr(){Release();}shared_ptr(const shared_ptr<T>& sp):_ptr(sp._ptr),_pCount(sp._pCount){(*_pCount)++;}void Release(){if (--(*_pCount) == 0 && _ptr){/*cout << "delete[]" << _ptr << endl;delete _ptr;*/D del;del(_ptr);delete _pCount;_pCount = nullptr;_ptr = nullptr;}}//sp1 = sp3shared_ptr<T>& operator=(shared_ptr<T>& sp){// 检测是否自身赋值//if (this != &sp)if (_ptr == sp._ptr) // 防止sp1 == sp2{Release();_ptr = sp._ptr;_pCount = sp._pCount;(*_pCount)++;}return *this;}//像指针一样T& operator*(){return *_ptr;}T* operator->(){return _ptr;}T* Get()const{return _ptr;}private:T* _ptr;int* _pCount;};template<class T>class weak_ptr{public:weak_ptr():_ptr(nullptr){}weak_ptr(const shared_ptr<T>& sp):_ptr(sp.Get()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){if (_ptr != sp.Get()){_ptr = sp.Get();}return *this;}private:T* _ptr;};
}
六、C+11和boost中智能指针的关系
- C++98中产生了第一个智能指针auto_ptr.
- C++boost给出了更实用的scoped_ptr和shared_ptr和weak_ptr.
- C++TR1,引入了shared_ptr等.不过注意的是TR1并不是标准版本.
- C++11中引入了unique_ptr,shared_ptr和weak_ptr.需要注意的是unique_ptr对应boost中的scoped_ptr.并且这些智能指针的实现原理是参考boost中实现的.
总结
(本章完)
相关文章:

C++ ---智能指针详解
文章目录前言一、 为什么需要智能指针?二、内存泄漏2.1 什么是内存泄露?危害是什么?2.2 内存泄露的分类2.3 如何避免内存泄露三、智能指针的使用及原理3.1 RAII3.2 智能指针的原理3.3 std::autoptr3.4 std::unique_ptr3.5 std::shared_ptrstd::shared_ptr的循环引…...

企业带宽控制管理
在企业中保持稳定的网络性能可能具有挑战性,因为采用数字化的网络可扩展性和敏捷性应该与组织的发展同步。随着基础设施的扩展、新应用和新技术的引入,网络的带宽容量也在增加。 停机和带宽过度使用是任何组织都无法避免的两个问题,为了解决…...

MybatisPlus实现分页效果并解决错误:cant found IPage for args!
前言 早就知道MybatisPlus对分页进行了处理,但是一直没有实战用过,用的是自己封装的一个分页组件,虽不说麻烦吧,但是也不是特别简单。 写起来还是比较复杂,但是最近这个组件有了点小小的bug,我决定是时候…...

C语言赋值(关系)运算符和逗号运算符
一.赋值(关系)运算符 1.关系运算符 高优先级组 < 左边值小于右边值,则返回1。否则返回0 < 左边值小于等于右边值,则返回1。否则返回0 > 左边值大于右边值,则返回1。否则返回0 > 左边值大于等于右边值,则返回1。否则返回0 低优先级组…...

几种在Linux/window下查询外网IP的办法。
hello world curl ifconfig.me/ip如下图 1. 纯文本 https://ifconfig.me/ip https://ipinfo.io/ip 或 https://ipecho.net/ip 或 https://ipecho.net/plain https://www.trackip.net/ip https://icanhazip.com 2. JSON格式 https://ifconfig.me/all.json https://ipi…...

【nodejs-05】黑马nodejs学习笔记05-数据库基本操作01
文章目录3.MySQL的基本使用3.1 使用 MySQL Workbench 管理数据库3.2 使用 SQL 管理数据库3.3 SQL 的 SELECT 语句3.4 SQL 的 INSERT INTO 语句3.5 SQL 的 UPDATE 语句3.6 SQL 的 DELETE 语句3.7 SQL 的 WHERE 子句3.8 SQL 的 AND 和 OR 运算符3.9 SQL 的 ORDER BY 子句3.10 SQL…...

零基础、学历无优势、逻辑能力一般”,能转行做程序员吗?
此前,拉勾数据研究院对程序员群体做了一次深入调查,并发布了《2022程序员群体职场洞察报告》,报告显示,“高薪”依然是程序员的职业标签之一。 在调查的程序员群体中,年薪在10-30万元之间的人数占比为66.7%࿰…...

第五章.与学习相关技巧—Batch Normalization
第五章.与学习相关技巧 5.3 Batch Normalization Batch Norm以进行学习时的mini_batch为单位,按mini_batch进行正则化,具体而言,就是进行使数据分布的均值为0,方差为1的正则化。Batch Norm是调整各层激活值的分布使其拥有适当的广…...

Zynq非Video Mixer方案实现视频叠加输出,无需SDK配置,提供工程源码和技术支持
目录1、前言2、Video Mixer的不便之处3、FDMA取代Video Mixer实现视频叠加输出4、Vivado工程详解5、上板调试验证并演示6、福利:工程代码的获取1、前言 关于Zynq使用Video Mixer方案实现视频叠加输出方案请参考点击查看:Video Mixer方案 对于Zynq和Micr…...

从零实现Web服务器(二): 线程池以及线程池的作用,Get和Post的区别,项目中如何编写数据库连接池,定时器优化非活跃连接
文章目录一、线程池以及线程池的作用二、手写线程池三、Get和Post的区别四、如何编写数据库连接池五、定时器优化非活跃连接5.1. 基于排序链表实现。5.2. 基于小根堆实现。5.3. 基于红黑树实现。5.4. 基于时间轮实现。5.4.1 单时间轮实现5.4.2 多时间轮实现一、线程池以及线程池…...

为什么伟大的产品只专注做一件事
uber 不允许你预订出租车。亚马逊一开始只是卖书。谷歌只是一个搜索引擎。麦当劳没有餐具。不知为什么,我们仍然相信一个产品要想成功,它必须做很多事情。这通常发生在两种情况下:当新产品试图让市场相信它们是值得的,或者当公司提…...

pycharm远程连接服务器,并单步调试服务器上的代码
每天都有不同的朋友来Push我 那如果比较健忘的话,为啥不问一下chatGPT呢 问题的缘由在我想在本地单步调试代码。。。 我的代码完全在云端服务器的,还有数据集都是,但实际上本地代码可以通过pycharm给他传上去。 但是在后面配置的时候需要两…...

JVM05 方法区
Person:存放在元空间,也可以说方法区 person:存放在Java栈的局部变量表中 new Person():存放在Java堆中 1.方法区的理解 方法区主要存放的是 Class,而堆中主要存放的是 实例化的对象 方法区(Method Area…...

盘点3个.Net开发的WMS仓库管理系统
更多开源项目请查看:一个专注推荐.Net开源项目的榜单 仓库管理系统在企业中,重要性越来越高,不仅可以提高效率,还能降低企业的压力,企业通过协调和优化资源使用和物料流动,能极大程度地提升了管理效率&…...
Linux下Java项目开机自动启动
Linux下Java项目开机自动启动1、在Linux上设置开机启动Java程序,例如:test.jar在Linux上启动Java程序的命令:2、可以将程序启动的指令做成一个shell脚本,简单的做法创建一个test.sh文件,内容如下:3、最重要的一步就是修…...

基于SpringBoot的智慧社区网站
文末获取源码 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏…...

数据分析与SAS学习笔记3
SAS在最新的展示图,表现力比较丰富。 SAS的处理流程: 数据步 过程步: ETL是数据分析非常重要的步骤。70%-90%花在收集数据以及整理数据,数据分析数据的时间不是很多的。 一个完整的数据步和过程步: 数据步基本语句总…...

天干地支蓝桥杯国赛
题目 分析 蓝桥杯国赛2020简单模拟题,你敢信,就是弄两个字符串数组。重点在于知道0000年是从哪个天干和地支开始的。 代码 #include <iostream> using namespace std;int year;int main() {cin >> year;string tiangan[10] {"geng&…...

Source lnsight工具的简单使用
多文件编程推荐用Source lnsight工具来进行编写 一、Source lnsight工具的简单使用 1、在桌面上新建一个文件夹factory,在文件夹里新建一个cat.c文件和si文件夹 2、打开Source lnsight工具,点击上方Project--->New Project 3、把文件夹factory中si文…...
100个变态的软件测试面试题及答案!——看完变态面试官对你竖起大拇指!
【纯干货!!!】花费了整整3天,整理出来的全网最实用软件测试面试大全,一共30道题目答案的纯干货,希望大家多多支持,建议 点赞!!收藏!!长文警告&…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...