智能指针
目录
1. 为什么需要智能指针?
2. 内存泄漏
2.1 什么是内存泄漏,内存泄漏的危害
2.2 内存泄漏分类(了解)
堆内存泄漏(Heap leak)
系统资源泄漏
2.3 如何检测内存泄漏(了解)
2.4如何避免内存泄漏
3.智能指针的使用及原理
3.1 RAII
// 使用RAII思想设计的SmartPtr类
编辑
std::auto_ptr
模拟实现
std::unique_ptr
编辑
编辑
模拟实现
编辑
模拟实现
赋值(重要)
总代码
循环引用问题
解决方法(weak_ptr不是智能指针)
模拟实现
测试:编辑
功能
语法
优点
示例
注意事项
定制删除器(用到了包装器)
题目
1. 为什么需要智能指针?
下面我们先分析一下下面这段程序有没有什么内存方面的问题?提示一下:注意分析MergeSort函数中的问题。
因为div抛异常后会跳过delete,导致内存泄漏
int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}void Func()
{// 1、如果p1这里new 抛异常会如何?// 2、如果p2这里new 抛异常会如何?// 3、如果div调用这里又会抛异常会如何?int* p1 = new int;int* p2 = new int;cout << div() << endl;delete p1;delete p2;
}int main()
{try{Func();}catch (exception& e){cout << e.what() << endl;}return 0;
}
2. 内存泄漏
2.1 什么是内存泄漏,内存泄漏的危害
什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内 存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对 该段内存的控制,因而造成了内存的浪费。 内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现 内存泄漏会导致响应越来越慢,最终卡死。
void MemoryLeaks()
{// 1.内存申请了忘记释放int* p1 = (int*)malloc(sizeof(int));int* p2 = new int;// 2.异常安全问题int* p3 = new int[10];Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.delete[] p3;
}
2.2 内存泄漏分类(了解)
C/C++程序中一般我们关心两种方面的内存泄漏:
堆内存泄漏(Heap leak)
堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一 块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分 内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
系统资源泄漏
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放 掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
2.3 如何检测内存泄漏(了解)
在linux下内存泄漏检测:Linux下几款C++程序中的内存泄露检查工具_c++内存泄露工具分析-CSDN博客
在windows下使用第三方工具:VS编程内存泄漏:VLD(Visual LeakDetector)内存泄露库_visual leak detector vs2020-CSDN博客
其他工具:内存泄露检测工具比较 - 默默淡然 - 博客园
2.4如何避免内存泄漏
1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps: 这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智 能指针来管理才有保证。
2. 采用RAII思想或者智能指针来管理资源。
3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。 总结一下:
内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄 漏检测工具。
3.智能指针的使用及原理
3.1 RAII
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内 存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在 对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做 法有两大好处:
不需要显式地释放资源。
采用这种方式,对象所需的资源在其生命期内始终保持有效。
// 使用RAII思想设计的SmartPtr类
int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}
//这样就不用担心没有释放了
template<class T>
class SmartPtr
{
public:// RAII// 资源交给对象管理,对象生命周期内,资源有效,对象生命周期到了,释放资源// 1、RAII管控资源释放// 2、像指针一样SmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){cout << "delete:" << _ptr << endl;delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;
};
void f()
{//new,也可能有很小的概率出问题SmartPtr<pair<string, string>> sp1(new pair<string, string>("1111", "22222"));//这里div抛异常后,sp1会释放,然后直接跳过进入main中不进入,sp2,sp3,只要是f结束,f中的new后都//会调用deletediv();SmartPtr<pair<string, string>> sp2(new pair<string, string>);SmartPtr<pair<string, string>> sp3(new pair<string, string>);SmartPtr<string> sp4(new string("xxxxx"));/*cout << *sp4 << endl;cout << sp1->first << endl;cout << sp1->second << endl;*///这里div抛异常后,sp1和sp2,sp3都会释放div();//delete p1;//cout << "delete:" << p1 << endl;
}
int main()
{try{f();}catch (const exception& e){cout << e.what() << endl;}catch (...){cout << "Unkown Exception" << endl;}return 0;
}
没写赋值,浅拷贝(深拷贝也没法解决问题),把sp2的值给了sp1,只释放了一个,还有一个没释放,发生了内存泄漏
c++中new了要delete
有了异常以后,已经不可控了,因为抛异常会影响执行流,会改变程序执行顺序
智能指针
using namespace std;
int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}
//这样就不用担心没有释放了
template<class T>
class SmartPtr
{
public:// RAII// 资源交给对象管理,对象生命周期内,资源有效,对象生命周期到了,释放资源// 1、RAII管控资源释放// 2、像指针一样SmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){cout << "delete:" << _ptr << endl;delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;
};
void f()
{//new,也可能有很小的概率出问题SmartPtr<pair<string, string>> sp1(new pair<string, string>("1111", "22222"));//这里div抛异常后,sp1会释放,然后直接跳过进入main中不进入,sp2,sp3,只要是f结束,f中的new后都//会调用deletediv();SmartPtr<pair<string, string>> sp2(new pair<string, string>);SmartPtr<pair<string, string>> sp3(new pair<string, string>);SmartPtr<string> sp4(new string("xxxxx"));/*cout << *sp4 << endl;cout << sp1->first << endl;cout << sp1->second << endl;*///这里div抛异常后,sp1和sp2,sp3都会释放div();//delete p1;//cout << "delete:" << p1 << endl;}int main()
{try{f();}catch (const exception& e){cout << e.what() << endl;}catch (...){cout << "Unkown Exception" << endl;}return 0;
}
std::auto_ptr
文档 https://cplusplus.com/reference/memory/auto_ptr/
auto_ptr是一个失败设计,很多公司明确要求不能使用auto_ptr
会导致悬空问题,实质上是管理权限的转移
C++98版本的库中就提供了auto_ptr的智能指针。下面演示的auto_ptr的使用及问题。
auto_ptr的实现原理:管理权转移的思想,下面简化模拟实现了一份bit::auto_ptr来了解它的原 理
// C++98 管理权转移 auto_ptr
int main()
{//这种形式跟上面自己写的Smartptr类似auto_ptr<int> at1(new int);//这个auto_ptr拷贝后会出现大问题,会出现悬空问题auto_ptr<int> at2(at1);//管理权限的转移*at2 = 10;cout << *at2 << endl;//*at1 = 10;会报错,因为*at1已经悬空*at1 = 10;cout << *at1 << endl;return 0;
}
模拟实现
namespace Ljw
{template<class T>class auto_ptr{public:auto_ptr(T* ptr):_ptr(ptr){}~auto_ptr(){cout << "~auto_ptr" << endl;if (_ptr){delete _ptr;}}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//重点在于拷贝auto_ptr(auto_ptr<T>& ptr):_ptr(ptr._ptr){//这里就是悬空了,管理权转ptr._ptr = nullptr;}private:T* _ptr;};
}
std::unique_ptr
C++11中开始提供更靠谱的unique_ptr
文档:https://cplusplus.com/reference/memory/unique_ptr/
unique_ptr的实现原理:简单粗暴的防拷贝,下面简化模拟实现了一份UniquePtr来了解它的原 理
/ C++11库才更新智能指针实现
// C++11出来之前,boost搞除了更好用的scoped_ptr/shared_ptr/weak_ptr // C++11将boost库中智能指针精华部分吸收了过来
// C++11->unique_ptr/shared_ptr/weak_ptr // unique_ptr/scoped_ptr // 原理:简单粗暴 -- 防拷贝
模拟实现
template<class T>
class unique_ptr
{
public://默认构造unique_ptr(T*ptr):_ptr(ptr){}~unique_ptr(){delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//直接用delete禁止拷贝构造unique_ptr(unique_ptr<T>& ptr) = delete;//直接用delete禁止赋值unique_ptr<T>& operator=(unique_ptr<T>& ptr) = delete;
private:T* _ptr;
};
std::shared_ptr
C++11中开始提供更靠谱的并且支持拷贝的shared_ptr
文档:https://cplusplus.com/reference/memory/shared_ptr/
shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。例如: 老师晚上在下班之前都会通知,让最后走的学生记得把门锁下。
1. shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共 享。
2. 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减 一。
3. 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
4. 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。
// 引用计数支持多个拷贝管理同一个资源,最后一个析构对象释放资源
原理图
模拟实现
用指针创建空间进行计数保存是合理的,静态全局的也是不符合的。
重点
赋值(重要)
步骤1:先把sp1和sp3弄成共同资源,先把sp2和sp4和sp5弄成共同资源
经过测试后,实际只有释放一个空间
//赋值
//要考虑到前后计数要改变
//如果到0了也是需要直接释放的
//如果是同一块资源赋值可以不用处理
//同一块资源的判定条件是
shared_ptr<T>& operator=(shared_ptr<T>& ptr)
{//同一块资源if (_ptr == ptr._ptr)return *this;//赋值的时候,this的空间计数就少了1(*_count)--;if (*(_count) == 0){delete _ptr;delete _count;}//先增加计数也一样然后ptr的空间资源计数就多了1//(*ptr._count)++;//赋值_ptr = ptr._ptr;_count = ptr._count;//然后ptr的空间资源计数就多了1(*_count)++;return *this;
}
总代码
template<class T>
class shared_ptr
{
public://默认构造shared_ptr(T* ptr=nullptr):_ptr(ptr),_count(new int(1))//这里_count是指针,要单独开一个空间,进行管理{}~shared_ptr(){(*_count)--;if ((* _count) == 0){cout << "~shared_ptr" << endl;delete _ptr;delete _count;} }T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//sp2(sp1)shared_ptr(shared_ptr<T>& ptr):_ptr(ptr._ptr),_count(ptr._count){(*_count)++;}//赋值//要考虑到前后计数要改变//如果到0了也是需要直接释放的//如果是同一块资源赋值可以不用处理//同一块资源的判定条件是shared_ptr<T>& operator=(shared_ptr<T>& ptr){//同一块资源if (_ptr == ptr._ptr)return *this;//赋值的时候,this的空间计数就少了1(*_count)--;if (*(_count) == 0){delete _ptr;delete _count;}//先增加计数也一样然后ptr的空间资源计数就多了1//(*ptr._count)++;//赋值_ptr = ptr._ptr;_count = ptr._count;//然后ptr的空间资源计数就多了1(*_count)++;return *this;}int use_count() const{return *_count;}T* get() const{return _ptr;}
private:T* _ptr;//计数int* _count;
};
循环引用问题
Node手动释放版本
delete n1上面如果抛异常了呢,所以就需要智能指针
这里报错的原因(类型不匹配)是因为一个自定义类型一个内置类型,要把上面的也改成智能指针,所以要改成如下图
正常释放(shared_ptr)
这样就发生了循环引用,没法正常释放空间,屏蔽其中一个就没问题,但两个都有就不行了
解决方法(weak_ptr不是智能指针)
/ 解决方案:在引用计数的场景下,把节点中的_prev和_next改成weak_ptr就可以了
// 原理就是,node1->_next = node2;和node2->_prev = node1;时weak_ptr的_next和
_prev不会增加node1和node2的引用计数。
模拟实现
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){_ptr = sp.get();return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;
};
测试:
make_shared
make_shared
是 C++11 标准库中引入的一个模板函数,它属于 <memory>
头文件中定义的智能指针工具集。make_shared
的主要目的是简化智能指针的创建过程,并可能提供性能上的优化。
以下是 make_shared
的一些关键点:
功能
make_shared
用于创建一个std::shared_ptr
对象,该对象管理动态分配的对象。- 它接受一个类型参数以及该类型构造函数所需的参数,并返回一个
shared_ptr
指向新创建的对象。
语法
template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
优点
-
简洁性:
make_shared
允许你在一条语句中创建和管理动态分配的对象,而不需要分别写new
和shared_ptr
的构造函数。 -
性能优化:
make_shared
通常比直接使用new
分配内存再包装成shared_ptr
更高效。这是因为make_shared
只需要在堆上分配一次内存,即同时为对象本身和共享的引用计数(控制块)分配空间。而直接使用new
和shared_ptr
的构造函数通常需要两次内存分配:一次为对象本身,另一次为控制块。 -
异常安全:当使用
new
分配内存并将结果传递给shared_ptr
的构造函数时,如果在参数传递过程中发生异常,可能会导致内存泄漏。使用make_shared
可以避免这种风险,因为new
和shared_ptr
的构造是在一个操作中完成的。
示例
下面是使用 make_shared
创建 std::shared_ptr
的一个例子:
#include <memory>
#include <iostream>class MyClass {
public:MyClass(int a, int b) : x(a), y(b) {}void print() const { std::cout << x << " " << y << std::endl; }private:int x, y;
};int main() {auto mySharedPtr = std::make_shared<MyClass>(10, 20);mySharedPtr->print(); // 输出: 10 20return 0;
}
注意事项
make_shared
不能用于管理动态分配的数组,因为这会导致shared_ptr
的析构函数使用错误的删除器(delete
而不是delete[]
)。- 当需要指定自定义的删除器时,使用
std::allocate_shared
而不是make_shared
。 - 在某些情况下,
make_shared
可能不是最佳选择,特别是当传递的参数涉及到类型转换或需要绑定引用时。
make_shared
是 C++ 中管理动态内存时非常有用的工具,可以减少代码量并提高性能。然而,了解其使用限制和最佳实践是编写高效、安全代码的关键。
定制删除器(用到了包装器)
unique和shared都有定制删除器
因为底层是delete,所以[ ]的释放要实现一个删除器
在shared_ptr中总代码
template<class T>
class shared_ptr
{
public://默认构造shared_ptr(T* ptr=nullptr):_ptr(ptr),_count(new int(1))//这里_count是指针,要单独开一个空间,进行管理{}template<class D>shared_ptr(T* ptr, D del)//这里就不可以加缺省值nullptr了,因为是从右到左的:_ptr(ptr), _count(new int(1))//这里_count是指针,要单独开一个空间,进行管理,_del(del){}~shared_ptr(){(*_count)--;if ((* _count) == 0){cout << "~shared_ptr" << endl;_del(_ptr);delete _count;} }T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//sp2(sp1)shared_ptr(shared_ptr<T>& ptr):_ptr(ptr._ptr),_count(ptr._count){(*_count)++;}//赋值//要考虑到前后计数要改变//如果到0了也是需要直接释放的//如果是同一块资源赋值可以不用处理//同一块资源的判定条件是shared_ptr<T>& operator=(shared_ptr<T>& ptr){//同一块资源if (_ptr == ptr._ptr)return *this;//赋值的时候,this的空间计数就少了1(*_count)--;if (*(_count) == 0){delete _ptr;delete _count;}//先增加计数也一样然后ptr的空间资源计数就多了1//(*ptr._count)++;//赋值_ptr = ptr._ptr;_count = ptr._count;//然后ptr的空间资源计数就多了1(*_count)++;return *this;}int use_count() const{return *_count;}T* get() const{return _ptr;}
private:T* _ptr;//计数int* _count;//删除器function<void(T*)> _del = [](T* ptr) {delete ptr; };
};
如果不是new出来的对象如何通过智能指针管理呢?其实shared_ptr设计了一个删除器来解决这 个问题(ps:删除器这个问题我们了解一下)
// 仿函数的删除器
// 仿函数的删除器template<class T>struct FreeFunc {void operator()(T* ptr){cout << "free:" << ptr << endl;free(ptr);}
};template<class T>struct DeleteArrayFunc {void operator()(T* ptr){ cout << "delete[]" << ptr << endl;delete[] ptr; }
};int main()
{FreeFunc<int> freeFunc;std::shared_ptr<int> sp1((int*)malloc(4), freeFunc);DeleteArrayFunc<int> deleteArrayFunc;std::shared_ptr<int> sp2((int*)malloc(4), deleteArrayFunc);std::shared_ptr<A> sp4(new A[10], [](A* p){delete[] p; });std::shared_ptr<FILE> sp5(fopen("test.txt", "w"), [](FILE* p)
{fclose(p); });return 0;
}
题目
1:
weak_ptr不能单独管理资源,必须配合shared_ptr一块使用,解决shared_ptr中存在的 循环引用问题
RAII的实现方式就是在构造函数中将资源初始化,在析构函数中将资源清理掉
RAII方式管理资源,可以有效避免资源泄漏问题
RAII方式管理锁,有些场景下可以有效避免死锁问题
2:
A.auto_ptr智能指针是在C++98版本中已经存在的
B.auto_ptr的多个对象之间,不能共享资源
C.auto_ptr的实现原理是资源的转移
3:
C++11中提供的智能指针都只能管理单个对象的资源,没有提供管理一段空间资源的智能指针
A.unique_ptr是C++11才正式提出的
C.unique_ptr不能使用其拷贝构造函数
D.unique_ptr的对象之间不能相互赋值
4:
有些场景下shared_ptr可能会造成循环引用,必须与weak_ptr配合使用
A.shared_ptr是C++11才正式提出来的
B.shared_ptr对象之间可以共享资源
D.shared_ptr是借助引用计数的方式实现的
5:
weak_ptr不能单独管理资源,因为其给出的最主要的原因是配合shared_ptr解决其循环 引用问题
weak_ptr和shared_ptr都是通过引用计数实现,但是在底层还是有区别的
weak_ptr的唯一作用就是解决shared_ptr中存在的循环引用问题,处理解决shared_ptr的循环引用问题外,别无它用
相关文章:

智能指针
目录 1. 为什么需要智能指针? 2. 内存泄漏 2.1 什么是内存泄漏,内存泄漏的危害 2.2 内存泄漏分类(了解) 堆内存泄漏(Heap leak) 系统资源泄漏 2.3 如何检测内存泄漏(了解) 2.4如何避免内存泄漏 3.…...

通过DevTools逃离Chrome沙盒(CVE-2024-6778和CVE-2024-5836)
介绍 这篇博文详细介绍了如何发现CVE-2024-6778和CVE-2024-5836的,这是Chromium web浏览器中的漏洞,允许从浏览器扩展(带有一点点用户交互)中进行沙盒逃逸。 简而言之,这些漏洞允许恶意的Chrome扩展在你的电脑上运行…...

手持无人机飞手执照,会组装调试入伍当兵有多香!
手持无人机飞手执照,并具备组装调试技能,在入伍当兵时确实会具有显著的优势和吸引力。以下是对这一情况的详细分析: 一、无人机飞手执照的优势 1. 法规遵从与安全保障: 根据《民用无人驾驶航空器系统驾驶员管理暂行规定》等相关…...
项目经理好累好烦啊,不想干了....
打住! 先问问自己,在所有的项目管理过程中,有没有体验到任和何乐趣。如果没有,请不要再继续内耗。 如果有,慎重考虑,然后适当解压,每个岗位都会不同的烦心事,每个企业都不完美&…...
论技术人员“技术人格”的重要意义
此论题从表面上看,是社会科学的,或者心理学的。然其对于信息技术这种科学的工作,又显得非常的重要。作为信息技术的从业者,或者说科学的从业者,具备良好的“技术人格”,对确保工作的质量,与正确…...

Kafka异常重试方案小记
背景 在最近进行的项目架构升级中,我们对原有的核心项目结构进行了细致的拆分。 现在,核心项目与非核心项目之间的通信和数据交换主要通过Kafka这一中间件来实现。 这种设计主要体现在核心项目向非核心项目发送通知,这些通知大致可以分为三个…...

非页面缓冲池占用过高处理方法
1.现象 电脑变莫名其妙得特别卡,明明16G的内存,理论上日常使用,打游戏之类的使用起来完全不会有什么大问题,但是实际使用却是卡的要死。 下面开始查找原因。 2.查找原因 使用win自带的任务管理器,可以看到日常内存…...

【Linux】进程信号(下)
目录 一、信号的阻塞 1.1 信号在内核中的保存方式 1.2 sigset_t信号集 (1)信号集操作 (2)sigprocmask函数 (3)sigpending函数 二、信号的处理 2.1 用户态和内核态 2.2 重谈进程地址空间 三、信号…...

FlinkCDC 实现 MySQL 数据变更实时同步
文章目录 1、基本介绍2、代码实战2.1、数据源准备2.2、代码实战2.3、数据格式 1、基本介绍 Flink CDC 是 Apache Flink 提供的一个功能强大的组件,用于实时捕获和处理数据库中的数据变更。可以实时地从各种数据库(如MySQL、PostgreSQL、Oracle、MongoDB…...

JavaWeb——Maven(4/8):Maven坐标,idea集成-导入maven项目(两种方式)
目录 Maven坐标 导入Maven项目 第一种方式 第二种方式 Maven坐标 Maven 坐标 是 Maven 当中资源的唯一标识。通过这个坐标,我们就能够唯一定位资源的位置。 Maven 坐标主要用在两个地方。第一个地方:我们可以使用坐标来定义项目。第二个地方&#…...

实现uniapp天地图边界范围覆盖
在uniapp中,难免会遇到使用地图展示的功能,但是百度谷歌这些收费的显然对于大部分开源节流的开发者是不愿意接受的,所以天地图则是最佳选择。 此篇文章,详细的实现地图展示功能,并且可以自定义容器宽高,还可…...
思科网络设备命令
一、交换机巡检命令 接口和流量状态 show interface stats:查看所有接口当前流量。show interface summary:查看所有接口当前状态和流量。show interface status:查看接口状态及可能的错误。show interface | include errors | FastEthernet …...
Egg.js使用ejs快速自动生成resetful风格的CRUD接口
目前的插件能够自动生成egg的crud的都不太好用 我们自己写一个吧 ejs模块 也方便定制 安装依赖 npm install ejs --save ejs 是一个简单易用的模板引擎,常用于 Node.js 应用程序中 在项目根目录下创建 template/controller.ejs 模板文件 use strict;const Co…...

自动化抖音点赞取消脚本批量处理
🌟 前言 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 &#x…...

基于YOLOv8深度学习的智能车牌检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战
背景及意义 智能车牌检测与识别系统通过使用最新的YOLOv8与PaddleOCR算法能够迅速、准确地在多种环境下实现实时车牌的检测和识别。本文基于YOLOv8深度学习框架,通过16770张图片,训练了一个进行车牌检测模型,可以检测蓝牌与绿牌,然后对检测到的车牌使用O…...

qt QGraphicsGridLayout详解
一、概述 QGraphicsGridLayout是Qt框架中用于在QGraphicsScene中布置图形项的一个布局管理器。它类似于QWidget中的QGridLayout,但主要处理的是QGraphicsItem和QGraphicsWidget等图形项。通过合理设置网格位置、伸缩因子和尺寸,可以实现复杂而灵活的布局…...
数字处理系列
(1)将数字转化成中文的过滤器 <template><div><p>数字转中文:{{ 110 | numberToChinese }}</p></div></template><script>export default {filters: {numberToChinese(num) {const chineseNums …...

基于开源Jetlinks物联网平台协议包-MQTT自定义主题数据的编解码
目录 前言 1.下载官方协议包 2.解压 3.自定义主题 4.重写解码方法 5.以下是我解析后接收到的数据 前言 最近这段时间,一直在用开源的Jetlinks物联网平台在学习,偶尔有一次机会接触到物联网设备对接,在协议对接的时候,遇到了…...

【Python】Python2.7升级Python3
需求背景 服务是跑在docker的容器里的,因此要新建image依赖环境是Ubuntu,老的是16.4。 步骤 先准备环境,因为只有你的环境上去了,运行代码的时候才会报错,这样才会把需要改的代码暴露出来。 python3.5目前也是被遗弃的…...
Python 内置函数 round() 详解
在 Python 编程中,round() 函数是一个非常实用的内置函数,用于对数字进行四舍五入。无论是在数据处理、财务计算还是科学计算中,round() 函数都能帮助我们得到所需的精确值。本文将详细介绍 round() 函数的用法和注意事项。 1. round() 函数…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...