智能指针
目录
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() 函数…...
JavaScript入门中-流程控制语句
本文转载自:https://fangcaicoding.cn/article/52 大家好!我是方才,目前是8人后端研发团队的负责人,拥有6年后端经验&3年团队管理经验,截止目前面试过近200位候选人,主导过单表上10亿、累计上100亿数据…...
kconfig语法(一)
一、安装Kconfiglib python -m pip install windows-curses python -m pip install kconfiglib二、使用样例 ①创建kconfig文件。 ②在kconfig文件添加内容: config KCONFIG_DEMO_ITEM1boolprompt "demonstate item1 for bool learning"config KCONFIG_DEMO_ITE…...
十七、行为型(命令模式)
命令模式(Command Pattern) 概念 命令模式是一种行为型设计模式,它将请求封装成一个对象,从而使您可以使用不同的请求对客户进行参数化,排队请求,以及支持可撤销操作。通过这种模式,调用操作的…...
原材料供应商的GRS认证证书过期了怎么办?
在全球纺织和时尚产业中,GRS(Global Recycle Standard,全球再生标准)认证已成为衡量企业环保和可持续发展的重要指标。然而,当原材料供应商的GRS认证证书过期时,企业需迅速采取行动,以确保供应链…...
C++编程:实现一个基于原始指针的环形缓冲区(RingBuffer)缓存串口数据
文章目录 0. 引言1. 使用示例2. 流程图2.1 追加数据流程2.2 获取空闲块流程2.3 处理特殊字符流程2.4 释放块流程2.5 获取下一个使用块流程 3. 代码详解3.1 Block 结构体3.2 RingBuffer 类3.3 主要方法解析append 方法currentUsed 和 currentUsing 方法release 方法nextUsed 方法…...
LangChain 创始人万字科普:手把手教你设计 Agent 用户交互
LangChain 可以算是 LLM 时代做 AI 应用开发必备的框架和平台,从模型选择、数据库链接与各种 Agent 搭建等,AI 应用的搭建、运行和管理都可以在 LangChain 上进行。 某种意义上,LangChain 可能是最了解 Agent(智能体)…...
Docker 用例:15 种最常见的 Docker 使用方法
容器化应用程序而不是将它们托管在虚拟机上是过去几年一直流行的概念,使容器管理流行起来。Docker 处于这一转变的核心,帮助组织无缝地采用容器化技术。最近,Docker 用例遍布所有行业,无论规模大小和性质如何。 什么是Docker&…...
若依 RuoYi4.6.0 代码审计
环境布置: 到官网下载源码:https://github.com/yangzongzhuan/RuoYi 采用phpstudy集成数据库,5.7版本。JDK1.8。 IDEA打开项目,等待自动加载,修改application-druid.yml配置文件:数据库名,账…...
C语言入门-选择结构
在编程中,我们经常需要根据不同的条件执行不同的操作。C语言为此提供了几种非常实用的选择结构:条件运算符、逻辑运算、if语句和switch语句。接下来,让我们深入探讨这些重要的知识点,帮助你更好地理解和掌握C语言的选择结构。 1.…...
Legion拯救者 刃7000K-26IAB联想台式机T5 26IAB7(90SU,90SV,90SW,90SX)原厂Windows11系统镜像下载
适用机型:【90SW、90SX、90SU、90SV】 链接:https://pan.baidu.com/s/1gJ4ZwWW2orlGYoPk37M-cg?pwd4mvv 提取码:4mvv lenovo联想原装WIN系统自带所有驱动、出厂主题专用壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软…...
太原seo网站建设/自助建站网站哪个好
此为记录下我自己的爬虫学习过程。 利用url包抓取网页 import urllib.request #url包 def main(): url "http://www.douban.com/" response urllib.request.urlopen(url) #请求 html response.read() #获取 html html.decode("utf-8") #解码 print(htm…...
可以做微课PPT模板 网站/百度关键词热度排名
一.自定义指令directive 除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作&a…...
专业网站建设价位/腾讯企业邮箱登录入口
同样以触摸屏的适配器tslib中的函数进行描述,如何从当前的环境变量中读取一个环境变量,并利进行文件的解析,下面先对几个程序看几个将要用到的函数: FILE * fopen(const char * path,const char * mode); 函数功能:…...
沧州英文模板建站/天津网站建设公司
//yy:那天考完概率论,上网无聊搜个期望可加性就搜到这题,看到以后特别有亲和感,挺有意思的。 hdu5194 DZY Loves Balls 【概率论 or 搜索】 题意: 一个盒子里有n个黑球和m个白球【n,m≤12】。每次随机从盒子里取走一个球ÿ…...
网站开发广告宣传语/上海百度推广电话
在画流程图时我们可以考虑使用模板进行套用使用,当然这是对新手来说开始的时候不熟悉绘制,我们可以考虑这样使用,那模板要在哪里寻找呢?下面是在迅捷画图中分享的流程图模板以及模板简介,希望可以帮助到大家。 财务…...
公网怎么做网站/海东地区谷歌seo网络优化
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m n))。 你可以假设 nums1 和 nums2 不会同时为空。 示例 1: nums1 [1, 3] nums2 [2]则中位数是 2.0示例 2: nums1 [1, 2] nums2 [3, 4]…...