当前位置: 首页 > news >正文

【C++】智能指针

前言

        上文我们学到了C++11的异常,了解到了C++与C语言处理错误的区别,异常的特点在于抛出与接收。【C++11】异常-CSDN博客

        本文我们来学习C++中的下一个功能:智能指针

1.智能指针的使用场景

        在上文我们知道了抛异常的知识,抛异常的“抛”这个动作一般来说是当程序出现了错误,抛出错误信息为了让我们解决。这个原本是解决错误的动作,在某些时候却称为了“铸就”错误的是罪魁祸首。

        比如:我们知道执行throw,这意味着在这个局部域中throw后面的语句将不再执行,跳过一段又一段程序直到找到匹配的catch时,才会从catch这个语句进行向下执行。那么一个局部域中如果在抛出异常时申请了空间,明明可以正常销毁的,但是却因为抛异常跳过了销毁空间的语句。这就导致一个及其严重的事故:内存泄漏

        在此之前,为了防止出现内存泄漏。我们通常是将抛出的异常再次捕获,执行销毁语句后,将异常重新抛出。但是这种方法并不太好用,所以为了更好的解决这个问题:智能指针诞生了

2.RAII和智能指针的设计思路 

        RAII(Resource Acquisition Is Initialization)是资源获取立即初始化的缩写。RAII是一种资源管理的类的设计思想,其本质就利用类的声明周期来管理资源,类的生命周期没结束时一直保持资源有效,类的生命周期结束时通过析构函数来释放资源。这样就可以保证出现上述情况时,资源可以正常的销毁,避免内存泄漏。(这里的资源可以是内存、文件指针、网络连接、互斥锁等等)

        智能指针除了会满足RAII的设计思路,还有考虑到访问资源的便捷性,所以智能指针还会重载operator * / operator -> / operator [ ]等运算符,便于访问。

#include<iostream>
using namespace std;template<class T>
class Smartptr
{
public:Smartptr(T* ptr):_ptr(ptr){ }~Smartptr(){cout << "~Smartptr" << endl;delete[] _ptr;_ptr = nullptr;}T* operator-> (){return _ptr;}T& operator* (){return *_ptr;}T& operator[] (size_t i){return _ptr[i];}private:T* _ptr;
};double Divide(int a, int b)
{//当除数为0时抛异常if (b == 0){string s = "除数为0";throw s;}return (double)a / b;
}void Func()
{//使用智能指针,抛异常后也可以正常释放Smartptr<int> p1 = new int[10];for (int i = 0; i < 10; i++)p1[i] = i;int a, b;cin >> a >> b;cout << Divide(a, b)<<endl;}int main()
{try{Func();}catch (const string& errid){cout << errid << endl;}
}

        当Func函数生命周期结束时,Smartptr会自动调用析构函数实现资源是释放。 

3.标准库中智能指针的使用

        标准库中的智能指针包含在头文件 <memory>

        智能指针是用于管理资源的,因此对于智能指针的拷贝来说,我们期望是拷贝出现的智能指针和和原指针共同管理这块资源的,而不是让拷贝出来的资源自己又去管理一个新资源。所以智能指针的拷贝只能是浅拷贝。浅拷贝就会面对一个问题:多次析构,而下面之所以有这么多不同的智能指针正式因为解决多次析构的方法不同导致的。

        auto_ptr,这个是C++98中提供的智能指针。它的特点是拷贝时将被拷贝对象的管理权转移给拷贝对象,这会导致拷贝对象悬空,当我们访问拷贝对象时就会报错。这是一个非常不好的设计,许多公司都是明令禁止使用这个智能指针的。

        unique_ptr,是C++11中提供的智能指针。其特点是不支持拷贝,只支持移动。如果不需要拷贝的情景下,非常推荐使用这个

        share_ptr,是C++11中提供的智能指针。其特点是支持拷贝,也支持移动。如果需要拷贝的场景推荐使用这个。其底层是使用引用计数实现的。

        weak_ptr,是C++11中提供的智能指针。虽然叫做智能指针但不太算得上,因为weak_ptr并不支持RAII,也就意味着weak_ptr并不能管理资源。weak_ptr的主要作用在于解决share_ptr的缺陷:循环引用。而循环引用带来的是内存泄漏。

#include<iostream>
#include<memory>
using namespace std;struct Date
{Date(int year = 0,int month = 0,int day = 0):_day(day),_month(month),_year(year){ }~Date(){cout << "~Date" << endl;}int _day;int _month;int _year;
};int main()
{auto_ptr<Date> ap1(new Date);//拷贝时,拷贝对象安排ap1会被悬空auto_ptr<Date> ap2(ap1);//此时访问ap1就会报错//ap1->_day;unique_ptr<Date> up1(new Date);//不支持拷贝//unique_ptr<Date> up2(up1);// //支持移动,但是移动后up1也被悬空unique_ptr<Date> up2(move(up1));shared_ptr<Date> sp1(new Date);//支持拷贝shared_ptr<Date> sp2(sp1);shared_ptr<Date> sp3(sp2);cout << sp1.use_count() << endl;cout << sp1->_year << endl;cout << sp2->_year << endl;cout << sp3->_year << endl;// ⽀持移动,但是移动后sp1也悬空,所以使用移动要谨慎 shared_ptr<Date> sp4(move(sp1));}

         智能指针析构时默认是使用delete释放资源,这就意味这当资源不是通过new申请时,将资源交给智能指针,析构时就会出问题

        为了解决这一问题,智能指针支持在构造函数里面给一个删除器。删除器其实就是一个可调用对象,我们按照自己想释放资源的方式实现删除器。智能指针接收后就会按照删除里实现的逻辑进行释放资源。

        因为使用delete[]释放资源的情况十分常用。使用库里面给我们专门特化了这个情况(share_ptr、unique_ptr均有特化版本)。只需要单独在尖括号里面加一对中括号即可。

        值得一提的是,删除器只能在构造时给出,并且后续不能修改。当shared_ptr利用已经存在的对象拷贝构造/赋值给新对象,这个新对象会继承其删除器,即使这并没有显示的写出。而unique_ptr则是将删除器移动给新对象

	shared_ptr<int[]> sp(new int[10]);shared_ptr<Date[]> sp(new Date[10]);
#include<iostream>
#include<memory>
using namespace std;//总结:使用shared_ptr,建议传Lambda和函数
//	   而使用unique_ptr,建议传Lambdastruct Date
{int _year;int _month;int _day;Date(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){ }~Date(){cout << "~Date()" << endl;}
};template<class T>
struct Delete
{void operator()(T* ptr){delete[] ptr;}
};int main()
{//直接传仿函数shared_ptr<Date> sp1(new Date[10], Delete<Date>());//给出Lambdashared_ptr<Date> sp2(new Date[10], [](Date* ptr) {delete[] ptr; });//值得一提的是unique_ptr与shared_ptr给出删除器的方法是不同的//由上面我们可以知道shared_ptr是在构造函数里面给出的//而unique_ptr的删除器是要在模板参数中给出,这就有点搞笑了unique_ptr<Date, Delete<Date>> up1(new Date[10]);//传函数到还可以,但是这个相传Lambda就麻烦了,因为Lambda并非类型而是对象//unique_ptr < Date, [](Date* ptr) {delete[] ptr; } > up2(new Date[10]);//具体要这样写才行,大家了解即可auto la = [](Date* ptr) {delete[] ptr; };unique_ptr< Date, decltype(la)> up2(new Date[10],la);
}

         shared_ptr除了支持用指针构造,还支持使用make_shared直接构造其好处是避免了空间的碎片化,因为shared_ptr内部成员除了指针还有一个引用计数。使用指针构造只是初始化了指针,还有一个引用计数没有初始化,为此编译器还会再去开辟空间用于初始化引用计数,而要是这种情况过多就会导致空间碎片化,不利用空间利用。而使用make_shared时就会将指针连同引用计数一起开辟,让这两个指针指向的空间连续。

        shared_ptr与unique_ptr都支持operator bool的类型转化。当智能指针的对象是一个空对象,没有管理资源,就会返回false,反之返回true。所以我们可以把智能指针的对象给if让其判断是否为空对象。

        shared_ptr和unique_ptr的构造函数都是用explicit修饰的,其目的是为了防止普通的指针隐式类型转换为智能指针类型。

int main()
{shared_ptr<Date> sp1 = make_shared<Date>(1, 2, 3);auto sp2 = make_shared<Date>(1, 2, 3);  //自动推导shared_ptr<Date> sp3;if (sp2)cout << "不是空对象" << endl;if (!sp3)cout << "是空对象" << endl;//报错,不允许隐式类型转化shared_ptr<Date> sp4 = new Date(1, 2, 3);shared_ptr<Date> sp5 = new Date(1, 2, 3);//仅支持显示类型转化shared_ptr<Date> sp6 = shared_ptr<Date>(new Date(1, 2, 3));
}

4.智能指针原理

        下面将模拟实现三个智能指针的实现思路

        auto_ptr和unique_ptr比较简单。auto_ptr会将管理权转移,不建议使用。unique_ptr不支持拷贝,仅支持移动,我们将拷贝禁用掉即可。

        重点关注:share_ptr。share_ptr是靠引用计数实现的,share_ptr内部会有一个计数器记录有多少个指针共同管理当前资源。初始化为1,当拷贝时就将计数器++析构时,当计数器不为1时仅将当前指针赋值为nullptr,当计数器为1时将计数器和资源释放

//auto_ptr模拟实现
//其特点是管理权转移,不建议使用!template<class T>
class auto_ptr
{auto_ptr(T* ptr):_ptr(ptr){ }//管理权限转移auto_ptr(const auto_ptr<T>& ap):_ptr(ap._ptr){ap._ptr = nullptr;}auto_ptr<T>& operator=(const auto_ptr<T>& ap){//检查是否赋值给自己if (_ptr != ap._ptr){//释放当前的资源if (_ptr)delete _ptr;_ptr = ap._ptr;ap._ptr = nullptr;}}~auto_ptr(){cout << "~auto_ptr" << endl;delete _ptr;_ptr = nullptr;}//像指针一样使用T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private:T* _ptr = nullptr;
};
//unique_ptr模拟实现
//unique_ptr不支持拷贝,仅支持移动template<class T>
class unique_ptr
{unique_ptr(T* ptr) :_ptr(ptr){}//不支持拷贝(禁用)unique_ptr(const unique_ptr<T>& up) = delete;unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;//支持移动unique_ptr(unique_ptr<T>&& up):_ptr(up._ptr){up._ptr = nullptr;}unique_ptr<T>& operator=(unique_ptr<T>&& up){if (_ptr != up._ptr){if (_ptr)delete _ptr;_ptr = up._ptr;up._ptr = nullptr;}}~unique_ptr(){cout << "~unique_ptr()" << endl;delete _ptr;_ptr = nullptr;}//像指针一样使用T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private:T* _ptr = nullptr;
};
//模拟实现shared_ptr
//其特点是支持拷贝、也支持移动,其底层是通过引用计数实现的
//这里添加了上述我们所将的删除器template<class T>
class shared_ptr
{shared_ptr(T* ptr):_ptr(ptr), _num(new int(1)){ }//添加删除器template<class D>shared_ptr(T* ptr,D del):_ptr(ptr),_num(new int(1)),_del(del){ }shared_ptr(const shared_ptr<T>& sp):_ptr(sp._ptr),_num(sp._num),_del(sp._del){ *(_num)++;}shared_ptr<T>& operator=(shared_ptr<T>& sp){if (_ptr != sp._ptr){//如果当前引用计数只有1时,直接释放资源if (_num == 1){delete _ptr;delete _num;_ptr = _num = nullptr;}_ptr = sp._ptr;*(_num)--;_num = sp._num;*(_num)++;_del = sp._del;}//返回*this主要是为了实现链式操作:a=b=creturn *this;}~shared_ptr(){if (*(_num) != 1){*(_num)--;_ptr = nullptr;}else{_del(_ptr);delete _num;_num = _ptr = nullptr;}}int use_count(){return *_num;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;int* _num; //引用计数//_del的类型是不确定的,利用包装器实现function<void(T*)> _del = [](T* ptr) {delete ptr; };
};

5.weak_ptr与shared_ptr

5.1share_ptr的循环引用

        目前有两个share_ptr对象:sp1、sp2。这两个的引用计数分别都为1。当sp1指向sp2时,sp2的引用计数为2,当sp2也指向sp1时,sp1的引用计数为2。这时程序结束,sp1进行销毁,引用计数不为1,仅进行减1操作。sp2进行销毁,引用计数不为1,仅进行减1操作。此时销毁操作结束,资源没有被释放,造成了内存泄漏。这就是循环引用带来的问题。

using namespace std;struct ListNode
{int _data;shared_ptr<ListNode> _next;shared_ptr<ListNode> _prev;// 这里改成weak_ptr,当n1->_next = n2时便于赋值~ListNode(){cout << "~ListNode()" << endl;}
};int main()
{shared_ptr<ListNode> sp1(new ListNode);shared_ptr<ListNode> sp2(new ListNode);cout << sp1.use_count() << endl;cout << sp2.use_count() << endl;//循环引用sp1->_next = sp2;sp2->_prev = sp1;//引用计数增加至2cout << sp1.use_count() << endl;cout << sp2.use_count() << endl;
}

         我们可以看到结果并没有调用析构函数。则表明循环引用的出现导致了内存泄漏。而C++11为了解决这一问题,设计出了weak_ptr

5.2weak_ptr

        weak_ptr严格意义上并不算智能指针,因为weak_ptr并不支持RAII,也不支持访问资源。weak_ptr在初始化的时候仅支持使用share_ptr初始化而weak_ptr并不会增加shared_ptr的引用计数,这就完美解决了上面导致循环引用的原因。

struct ListNode
{int _data;//shared_ptr<ListNode> _next;//shared_ptr<ListNode> _prev;// 这里改成weak_ptr,当n1->_next = n2;绑定shared_ptr时 // 不增加n2的引用计数,不参与资源释放的管理,就不会形成循环引用了 weak_ptr<ListNode> _next;weak_ptr<ListNode> _prev;~ListNode(){cout << "~ListNode()" << endl;}
};int main()
{shared_ptr<ListNode> sp1(new ListNode);shared_ptr<ListNode> sp2(new ListNode);cout << sp1.use_count() << endl;cout << sp2.use_count() << endl;//未使用weak_ptr将导致循环引用sp1->_next = sp2;sp2->_prev = sp1;//未使用weak_ptr引用计数将增加至2cout << sp1.use_count() << endl;cout << sp2.use_count() << endl;
}

 

         weak_ptr是没有重载operator*/operator->之类的运算符的,weak_ptr是不支持访问资源的,因为如果当weak_ptr绑定shared_ptr的资源已经释放了,这个时候weak_ptr再去访问就很危险了。 

        weak_ptr支持expired检查指向的资源是否过期,weak_ptr也可以使用use_count得到shared_ptr的引用计数个数

        如果weak_ptr想要访问资源可以使用lock,lock会返回一个管理资源的shared_ptr。如果资源已经释放,则返回一个空对象。如果没有释放则返回一个shared_ptr的对象。通过lock返回的shared_ptr对象访问资源是安全的。

#include<iostream>
#include<memory>
using namespace std;int main()
{shared_ptr<int> sp1(new int(1));shared_ptr<int> sp2(sp1);weak_ptr<int> wp1(sp2);cout << wp1.use_count() << endl; 	//weak_ptr不增加引用计数cout << wp1.expired() << endl;      //资源没有被释放,有效//通过lock访问资源auto sp = wp1.lock();*sp += 9;cout << *sp << endl;cout << *sp1 << endl;//资源被释放后,无效//引用计数不断的减少,为0时资源释放sp1 = make_shared<int>(1);cout << wp1.use_count() << endl;cout << wp1.expired() << endl;sp2 = make_shared<int>(1);cout << wp1.use_count() << endl;cout << wp1.expired() << endl;}

相关文章:

【C++】智能指针

前言 上文我们学到了C11的异常&#xff0c;了解到了C与C语言处理错误的区别&#xff0c;异常的特点在于抛出与接收。【C11】异常-CSDN博客 本文我们来学习C中的下一个功能&#xff1a;智能指针 1.智能指针的使用场景 在上文我们知道了抛异常的知识&#xff0c;抛异常的“抛”这…...

Adobe Acrobat pro在一份PDF中插入空白页

在Adobe Acrobat pro中先打开我们的PDF文件&#xff1b; 用鼠标点击需要插入空白页处的上一页&#xff1b; 然后如下图操作&#xff1a; 默认会在光标处的下一页插入一张空白页&#xff0c;你也可以修改插入页的页码或者向前一页插入...

Oracle adg环境下调整redo日志组以及standby日志组大小

1.在adg环境中&#xff0c;调整redo日志组大小以及standby日志组大小主要思路如下&#xff1a; a、先备库增加standby redo 删除老standby redo, b、然后主库增加redo删除老redo, c、备库增加新redo删除老redo, d、最后主库增加standby redo。 #主库 [oracleDB196 ~]$ sql / a…...

Nlog适配达梦数据库进行日志插入

前言 原来使用的是SQLServer数据库&#xff0c;使用Nlog很流畅&#xff0c;没有什么问题。现在有个新项目需要使用麒麟操作系统和达梦数据库&#xff0c;业务流程开发完成之后发现Nlog配置文件中把数据库连接内容修改之后不能执行插入操作。 原Nlog.config配置 <?xml ve…...

记一次redis未授权被种挖矿

#挖矿程序 /etc/httpgd /etc/nnt.sh #大小问 #定时任务名为root /var/spool/cron/root 内容&#xff1a;*/50 * * * * sh /etc/nnt.sh >/dev/null 2>&1 定时任务只有所有者可以写&#xff0c;且chmod修改权限失败。 #先查看定时任务的拓展属性&#xff0c;不可变(i…...

Docker私有仓库实战:官方registry镜像实战应用

抱歉抱歉&#xff0c;离职后反而更忙了&#xff0c;拖了好久&#xff0c;从4月拖到现在&#xff0c;在学习企业级方案Harbor之前&#xff0c;我们先学习下官方方案registry&#xff0c;话不多说&#xff0c;详情见下文。 注意&#xff1a;下文省略了基本认证 TLS加密&#xff…...

LeetCode 热题 100_只出现一次的数字(96_136_简单_C++)(哈希表;哈希集合;排序+遍历;位运算)

LeetCode 热题 100_只出现一次的数字&#xff08;96_136_简单_C&#xff09; 题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;思路一&#xff08;哈希表&#xff09;&#xff1a;思路二&#xff08;哈希集合&#xff09;&#xff1a;思路三…...

基于FastAPI框架的日志模块设计

以下是一个基于FastAPI框架设计的日志模块&#xff0c;结合SQLite数据库实现增删改查功能的完整实现方案&#xff1a; 1. 项目结构 your_project/ ├── app/ │ ├── logs/ # 日志模块目录 │ │ ├── models.py # 数据库模型定义 │ │ …...

网页禁止粘贴的解决方法(以学习通网页为例)

网页禁止粘贴的解决方法&#xff08;以学习通网页为例&#xff09; 学数据挖掘&#xff0c;学习通过作业的简答题要英文做答还竟然不能复制粘贴&#xff0c;受不了了 下面给出解决办法 1.想着是网页JS的问题&#xff0c;既然不能直接粘贴&#xff0c;那就在源码里面修改 2.于…...

Linux常用命令详解(下):打包压缩、文本编辑与查找命令

一、打包压缩命令 在Linux系统中&#xff0c;打包与压缩是文件管理的核心操作之一。不同的工具适用于不同场景&#xff0c;以下是最常用的命令详解&#xff1a; 1. tar命令 作用&#xff1a;对文件进行打包、解包、压缩、解压。 语法&#xff1a; tar [选项] [压缩包名] […...

前端面经 计网 http和https区别

HTTP 超文本传输 忒点&#xff1a; 支持CS 客户/服务器模式 方便快捷 简单 允许传输任意类型的数据 在报文头中的Content-Type中声明 无连接&#xff0c;一次连接仅处理一个请求 无状态 不保留上一次的状态 HTTPS 解决HTTP明文传输 在HTTP基础上增加SSL协议 HTTP版本 …...

mac一键安装gpt-sovit教程中,homebrew卡住不动的问题

mac一键安装gpt-sovit教程 仅作为安装过程中解决homebrew卡住问题的记录 资源地址 https://www.yuque.com/baicaigongchang1145haoyuangong/ib3g1e/znoph9dtetg437xb#mlAoP 下载一键包 下载后并解压&#xff0c;找到install for mac.sh&#xff0c;终端执行bash空格拖拽in…...

05_jdk8新特性

文章目录 一、jdk8新特性1. Lambda表达式2. Stream API3. 函数式接口4. 默认方法5. 方法引用6. 新的日期和时间API7. Optional类8. 并发增强 二、常用函数式接口1. Supplier<T>2. Consumer<T>3. Function<T,R>4. Predicate<T> 一、jdk8新特性 JDK 8&a…...

解决IDEA Maven编译时@spring.profiles.active@没有替换成具体环境变量的问题

如果不加filtering true&#xff0c;编译后的文件还是 spring.profiles.active 编译前的application.yml 编译后的application.yml【环境变量没有改变】 解决方案 找到 SpringBoot 启动类所在的pom.xml&#xff0c;在 resources 增加 filtering true&#xff0c;然后重新…...

HTML17:表单初级验证

表单初级验证 常用方式 placeholder 提示信息 <p>名字:<input type"text" name"username" maxlength"8" size"30" placeholder"请输入用户名"></p>required 非空判断 <p>名字:<input type"…...

vue3+dhtmlx-gantt实现甘特图展示

最终效果 数据源demo {"data": [{"actual_end_date": "2025-04-23","actual_start_date": "2025-04-15","duration": 10,"end_date": "2025-05-01","id": "2|jvUiek",&…...

Jupyter-AI Pandas-AI本地使用功能优化

引言 Jupyter-ai 和 Pandas-ai 的优化主要是个人工作遇到的需求,个人觉得是一个不错的体验优化,所以进行分享仅供参考,不喜勿喷,共同进步!Jupyter-AI优化主要包含以下方向(当前已实现): Jupyter-AI中 Chat 扩展和 NoteBook 的 Cell 工作去部分,使用的Language Model 和 …...

Model.eval() 与 torch.no_grad() PyTorch 中的区别与应用

Model.eval() 与 torch.no_grad(): PyTorch 中的区别与应用 在 PyTorch 深度学习框架中&#xff0c;model.eval() 和 torch.no_grad() 是两个在模型推理&#xff08;inference&#xff09;阶段经常用到的函数&#xff0c;它们各自有着独特的功能和应用场景。本文将详细解析这两…...

mac M2下的centos8:java和jenkins版本匹配,插件安装问题

java和jenkins版本匹配如下&#xff1a; Java Support Policy 如果版本不匹配&#xff0c;jenkins无法正常启动&#xff0c;插件也无法安装成功。 实际操作过程发现&#xff1a;表格也并不全然正确&#xff0c;还是需要特定的版本才能正常 参考如下&#xff1a; jenkins安装…...

PyTorch 中的 Autograd 实现细节解析和应用

摘要: 本文深入探讨 PyTorch 框架的核心组件之一——Autograd 机制。我们将解析其内部工作原理,包括计算图的构建、梯度的计算与传播,并探讨其在神经网络训练、模型调试及可解释性等方面的广泛应用。 通过理解 Autograd 的实现细节,开发者可以更高效地利用 PyTorch 进行深度…...

【AI提示词】波特五力模型专家

提示说明 具备深入对企业竞争环境分析能力的专业人士。 提示词 # Role:波特五力模型专家## Profile - language:中文 - description:具备深入对企业竞争环境分析能力的专业人士 - background:熟悉经济学基础理论&#xff0c;擅长用五力模型分析行业竞争 - personality…...

python 的 ​uv、pip​ 和 ​conda​ 对比和技术选型

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…...

《Python星球日记》 第63天:文本方向综合项目(新闻分类)

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、项目需求分析1. 项目背景与目标2. 功能需求3. 技术方案概述 二、数据清洗与…...

面试题:请解释Java中的设计模式,并举例说明单例模式(Singleton Pattern)的实现方式

Java中的设计模式 设计模式是在软件开发过程中针对特定场景而使用的通用解决方案。设计模式可以帮助开发者编写出更加清晰、灵活和可维护的代码。设计模式分为三大类&#xff1a; 创建型模式&#xff1a;用于对象的创建过程&#xff0c;如单例模式、工厂模式、建造者模式等。…...

MySQL全量、增量备份与恢复

目录 一&#xff1a;MySQL数据库备份概述 1.数据备份的重要性 2.数据库备份类型 2.1从物理与逻辑的角度分类 物理备份 逻辑备份 2.2从数据库的备份策略角度分类 完全备份 差异备份 增量备份 3.常见的备份方法 3.1物理冷备份 3.2专用备份工具 MySQL dump或MySQL hot…...

rust 全栈应用框架dioxus server

接上一篇文章dioxus全栈应用框架的基本使用&#xff0c;支持web、desktop、mobile等平台。 可以先查看上一篇文章rust 全栈应用框架dioxus&#x1f448; 既然是全栈框架&#xff0c;那肯定是得有后端服务的&#xff0c;之前创建的服务没有包含后端服务包&#xff0c;我们修改…...

Clinica集成化的开源平台-神经影像研究

Clinica集成化的开源平台-神经影像研究 &#x1f31f; Clinica集成化的开源平台-神经影像研究引言 &#x1f6e0;️ 一、环境搭建与数据准备1. 安装Clinica&#xff08;附避坑指南&#xff09;2. 数据标准化&#xff08;BIDS格式处理&#xff09; &#x1f9e0; 二、sMRI预处理…...

LabVIEW中算法开发的系统化解决方案与优化

在 LabVIEW 开发环境中&#xff0c;算法实现是连接硬件数据采集与上层应用的核心环节。由于图形化编程范式与传统文本语言存在差异&#xff0c;LabVIEW 中的算法开发需要特别关注执行效率、代码可维护性以及与硬件资源的适配性。本文从算法架构设计、性能优化到工程实现&#x…...

【Pandas】pandas DataFrame cov

Pandas2.2 DataFrame Computations descriptive stats 方法描述DataFrame.abs()用于返回 DataFrame 中每个元素的绝对值DataFrame.all([axis, bool_only, skipna])用于判断 DataFrame 中是否所有元素在指定轴上都为 TrueDataFrame.any(*[, axis, bool_only, skipna])用于判断…...

【递归、搜索与回溯】专题一:递归(一)

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人递归&#xff0c;搜索与回溯算法的学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码…...

pythonocc 拉伸特征

micromamba install -c conda-forge pythonocc-core opencascade.js安装不起来&#xff0c;ai用pythonocc练个手 拉伸线框 线成面 from OCC.Core.gp import gp_Pnt, gp_Dir, gp_Vec from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire f…...

防爆手机与普通手机有什么区别

在石油化工、矿山能源、危化品运输等特殊行业中&#xff0c;一部手机的选择可能直接关系到生产安全与人员生命。防爆手机作为工业安全通信的核心工具&#xff0c;与日常使用的普通手机存在本质差异。本文将从技术原理、安全标准、功能设计及适用场景等维度&#xff0c;解析二者…...

动手学深度学习12.3.自动并行-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;无 本节教材地址&#xff1a;12.3. 自动并行 — 动手学深度学习 2.0.0 documentation 本节开源代…...

第二十二天打卡

数据预处理 import pandas as pd from sklearn.model_selection import train_test_splitdef data_preprocessing(file_path):"""泰坦尼克号生存预测数据预处理函数参数:file_path: 原始数据文件路径返回:preprocessed_data: 预处理后的数据集""&quo…...

SET NX互斥功能的实现原理

Redis 的 SET key value NX 命令通过其原子性和底层数据结构的特性实现互斥功能&#xff0c;具体实现如下&#xff1a; 1. 互斥功能的实现原理 SET NX 的核心是 原子性操作&#xff1a;当且仅当键&#xff08;key&#xff09;不存在时&#xff0c;才会设置键的值。Redis 的单线…...

前端 CSS 样式书写与选择器 基础知识

1.CSS介绍 CSS是Cascading Style Sheet的缩写&#xff0c;中文意思为"层叠样式表"&#xff0c;它是网页的装饰者&#xff0c;用来修饰各标签 排版(大小、边距、背景、位置等)、改变字体的样式(字体大小、字体颜色、对齐方式等)。 2.CSS书写位置 2.1 样式表特征 层…...

一小时学会Docker使用!

文章目录 前言一、安装ssh连接工具二、安装docker三、Docker常见命令四、docker-compose使用 前言 Docker&#xff1a; Docker简单来说就是简化环境配置的&#xff0c;我们配置环境只需要简单的docker pull&#xff0c;docker run即可&#xff0c;而删除环境也很容易&#xff…...

android studio开发aar插件,并用uniapp开发APP使用这个aar

android studio开发aar插件&#xff0c;并用uniapp开发APP使用这个aar 使用android studio打包aar和Unity导入aar详解...

操作系统实战——QEMU模拟器搭建【rCore 操作系统】

操作系统大作业——QEMU模拟器搭建rCore操作系统 按照本篇步骤走&#xff0c;帮你少走很多弯路&#xff01;博主在自己做的过程中踩了很多坑&#xff0c;过程还是很痛苦的&#xff0c;走了很多弯路&#xff0c;现在都已经在文章中把坑填平了&#xff0c;把弯路修直了。 创作不易…...

web:InfiniteScroll 无限滚动

InfiniteScroll 无限滚动 分页加载 <div class"data-box" v-infinite-scroll"loadMore"> <li v-fori in dataList></li> </div>form: {current: 1,size: 10,}loadMore(){console.log(this.dataList.length, this.total ,8888)if…...

【Redis 进阶】哨兵模式

思维导图&#xff1a; 一、哨兵模式概述 &#xff08;一&#xff09;传统主从复制模式的局限性 在传统的Redis主从复制架构中&#xff0c;若主节点发生故障&#xff0c;运维人员需手动执行故障转移操作&#xff0c;将一个从节点提升为新主节点&#xff0c;并逐一通知所有客户…...

告别卡顿,图片查看界的“速度与激情”

嘿&#xff0c;小伙伴们&#xff01;今天电脑天空给大家介绍一款超好用的图片查看神器——ImageGlass&#xff01;这可不是普通的图片查看软件哦&#xff0c;它简直就是图片界的“全能王”。首先&#xff0c;它能打开的图片格式多到让你眼花缭乱&#xff0c;什么PNG、JPEG、GIF…...

02_线性模型(回归分类模型)

用于分类的线性模型 线性模型也广泛应用于分类问题&#xff0c;可以利用下面的公式进行预测&#xff1a; $ \widehat y w[0]*x[0]w[1]*x[1]…w[p]*x[p]b > 0$ 公式看起来与线性回归的公式非常相似&#xff0c;但没有返回特征的加权求和&#xff0c;而是为预测设置了阈值…...

力扣2094题解

记录&#xff1a; 2025.5.12 题目&#xff1a; 思路&#xff1a; 暴力遍历。 解题步骤&#xff1a; 1.统计数字出现次数&#xff1a;使用数组cnt来记录输入数组中每个数字的出现次数。 2.生成三位偶数&#xff1a;通过循环从100开始&#xff0c;每次递增2&#xff0c;生成…...

人物角色设定机制

模块一&#xff1a;角色塑造进阶技巧 将角色设定(Character Headcanon)提升至更高层次 当您通过Character Headcanon Generator生成基础设定后&#xff0c;可运用以下专业技巧深化角色塑造&#xff1a; 情感核心图谱分析法 解构角色情感驱动机制及其情境表现&#xff1a; 主…...

Python动态渲染页面抓取之Selenium使用指南

目录 一、Selenium技术架构解析 二、环境搭建与基础配置 1. 组件安装 2. 驱动配置 3. 基础操作模板 三、动态内容抓取核心策略 1. 智能等待机制 2. 交互行为模拟 3. 反爬应对方案 四、实战案例&#xff1a;电商评论抓取 五、性能优化与异常处理 2. 异常捕获 六、进…...

智能手表 MCU 任务调度图

智能手表 MCU 任务调度图 处理器平台&#xff1a;ARM Cortex-M33 系统架构&#xff1a;事件驱动 多任务 RTOS RTOS&#xff1a;FreeRTOS&#xff08;或同类实时内核&#xff09; 一、任务调度概览 任务名称优先级周期性功能描述App_MainTask中否主循环调度器&#xff0c;系统…...

【C++】cout的格式输出

目录 一、cout的格式输出1、控制宽度和填充2、控制数值格式3、控制整数格式4、控制对齐方式 个人主页<—请点击 C专栏<—请点击 一、cout的格式输出 printf函数在输出数据的时候&#xff0c;可以指定格式来输出&#xff0c;比如&#xff1a;指定宽度、指定小数点后的位…...

私域流量新阵地:掌握Telegram私域运营全方法

在流量获取成本不断上升的今天&#xff0c;越来越多企业和品牌开始将目光转向“私域流量”——一条可以长期沉淀用户、反复转化的可持续增长之路。而在全球化趋势下&#xff0c;Telegram作为一款以高自由度、强隐私性著称的即时通讯平台&#xff0c;正在成为私域运营的新阵地。…...

Python Day23 学习

继续SHAP图绘制的学习 1. SHAP特征重要性条形图 特征重要性条形图&#xff08;Feature Importance Bar Plot&#xff09;是 SHAP 提供的一种全局解释工具&#xff0c;用于展示模型中各个特征对预测结果的重要性。以下是详细解释&#xff1a; 图的含义 - 横轴&#xff1a;表示…...