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

C++笔记---智能指针

1. 什么是智能指针

1.1 RALL设计思想

RAII(Resource Acquisition Is Initialization,资源获取即初始化)是一种资源管理类的设计思想,广泛应用于C++等支持对象导向编程的语言中。它的核心思想是将资源的管理与对象的生命周期紧密绑定,通过在对象的构造函数中获取资源,并在析构函数中释放资源,以此来确保资源总是被正确管理,避免资源泄露等问题。RAII利用了C++中对象自动调用析构函数的特性,即使在发生异常的情况下,也能保证资源被适时释放

1.2 智能指针的概念

智能指针是C++标准库中的一种高级指针管理工具,它们通过自动管理动态分配的内存来帮助预防内存泄漏和其他资源管理错误。

简单来说,智能指针是包装了指针的类,当智能指针对象的生命周期结束时,其析构函数会对指针指向的动态资源进行释放。

也就是说,我们将动态申请的内存交给智能指针对象来管理,将其的生命周期与智能指针的生命周期进行绑定,以此实现对动态分配的内存的自动释放。

智能指针相当于是给普通的指针加上了一个自动释放资源的功能,在行为上模拟普通指针的行为,重载了各种指针相关的操作符(operator*、operator->、operator[]等),因此叫做智能指针。

1.3 智能指针的应用场景

在C++中,智能指针的引入是为了简化和自动化内存管理,特别是在处理动态分配内存时,智能指针能够帮助防止常见的内存错误,如内存泄漏、悬挂指针和双重删除等。

在C++11之前,程序员需要手动管理动态分配的内存,这要求他们在适当的时机使用new和delete操作符来分配和释放内存。

这种管理方式不仅容易出错,而且在遇到异常时尤其难以保证资源被正确清理。

下面程序中我们可以看到,假如异常被抛出,就会导致array1和array2未被正常释放。

我们要处理这种情况,可以考虑先将异常捕获并将资源释放之后重新抛出,但这样的做法可维护性差,每此申请动态资源都需要再catch块中新增释放操作。除此之外,假如程序的其他部分抛出了异常(例如new也可能抛出异常),catch块中的释放操作也不会被执行。

double Divide(int a, int b)
{// 当b == 0时抛出异常if (b == 0){throw "Divide by zero condition!";} else{return (double)a / (double)b;}
}void Func()
{int* array1 = new int[10];int* array2 = new int[10];try{int len, time;cin >> len >> time;cout << Divide(len, time) << endl;} catch(...){cout << "delete []" << array1 << endl;cout << "delete []" << array2 << endl;delete[] array1;delete[] array2;throw; // 异常重新抛出,捕获到什么抛出什么} // ...cout << "delete []" << array1 << endl;delete[] array1;cout << "delete []" << array2 << endl;delete[] array2;
} int main()
{try{Func();} catch(const char* errmsg){cout << errmsg << endl;} catch(const exception & e){cout << e.what() << endl;} catch(...){cout << "未知异常" << endl;} return 0;
}

当引入智能指针之后,操作起来就要简单得多了:

template<class T>
class SmartPtr
{
public:// RAIISmartPtr(T* ptr): _ptr(ptr){}~SmartPtr(){cout << "delete[] " << _ptr << endl;delete[] _ptr;}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)
{// 当b == 0时抛出异常if (b == 0){throw "Divide by zero condition!";} else{return (double)a / (double)b;}
}void Func()
{SmartPtr<int> array1(new int[10]);SmartPtr<int> array2(new int[10]);int len, time;cin >> len >> time;cout << Divide(len, time) << endl;
}int main()
{try{Func();} catch(const char* errmsg){cout << errmsg << endl;} catch(const exception & e){cout << e.what() << endl;} catch(...){cout << "未知异常" << endl;} return 0;
}


2. C++标准库中的智能指针

智能指针在设计时存在一个较大的难题:那就是拷贝时的行为如何设计?

假如我们直接将一个智能指针内部的指针拷贝给另一个智能指针,那么当两个智能指针的生命周期都结束时,同一个动态资源就会被释放两次。

针对这个问题,C++标准库中给出了几种不同的方案,这些智能指针都在<memory>这个头文件下面,我们包含<memory>就可以使用了。

其中weak_ptr比较特殊,它仅用于辅助shared_ptr处理循环引用的问题,我们在第3部分再解释。

2.1 std::auto_ptr

auto_ptr是C++98时设计出来的智能指针,他的特点是拷贝时把被拷贝对象的资源的管理权转移给拷贝对象,这是一个非常糟糕的设计,因为他会到被拷贝对象悬空,访问报错的问题,C++11设计出新的智能指针后,强烈建议不要使用auto_ptr

C++11出来之前很多公司也是明令禁止使用这个智能指针的。

个人感觉auto_ptr是最贴合设计初衷的名字,应该给下面行为最接近普通指针shared_ptr使用,但可惜好名字被狗用了。

实现示例:

namespace lbz
{template<class T>class auto_ptr{public:auto_ptr(T* ptr): _ptr(ptr){}auto_ptr(auto_ptr<T>& sp):_ptr(sp._ptr){// 管理权转移sp._ptr = nullptr;}auto_ptr<T>& operator=(auto_ptr<T>& ap){// 检测是否为⾃⼰给自己赋值if (this != &ap){// 释放当前对象中资源if (_ptr)delete _ptr;// 转移ap中资源到当前对象中_ptr = ap._ptr;ap._ptr = NULL;}return*this;}~auto_ptr(){if (_ptr){cout << "delete:" << _ptr << endl;delete _ptr;}} // 像指针一样使用T & operator*(){return *_ptr;} T* operator->(){return _ptr;}private:T* _ptr;};
}

2.2 std::unique_ptr

std::unique_ptr是一种独占所有权的智能指针,它确保在任何时刻只有一个unique_ptr实例可以拥有和管理所指向的对象。一旦unique_ptr实例超出其作用域或被显式重置,它所管理的对象将被自动释放。

unique_ptr不支持拷贝操作,但可以通过移动语义来转让所有权。

实现示例
namespace lbz
{template<class T>class unique_ptr{public:explicit unique_ptr(T* ptr):_ptr(ptr){}~unique_ptr(){if (_ptr){cout << "delete:" << _ptr << endl;delete _ptr;}}// 像指针⼀样使用T & operator*(){return *_ptr;} T* operator->(){return _ptr;} // 禁止直接拷贝unique_ptr(const unique_ptr<T>& sp) = delete;unique_ptr<T>& operator=(const unique_ptr<T>& sp) = delete;unique_ptr(unique_ptr<T>&& sp):_ptr(sp._ptr){sp._ptr = nullptr;} unique_ptr<T>& operator=(unique_ptr<T>&& sp){delete _ptr;_ptr = sp._ptr;sp._ptr = nullptr;}private:T* _ptr;};
}

2.3 std::shared_ptr

std::shared_ptr提供了共享所有权的智能指针,允许多个shared_ptr实例共享同一个对象的所有权。对象的生命周期由最后一个持有该对象的shared_ptr实例决定。当没有任何shared_ptr实例指向该对象时,对象会被自动释放。

shared_ptr是行为最贴近普通指针的智能指针,实践当中的使用最多,所以一般提到智能指针默认就是指shared_ptr。

shared_ptr的原理

shared_ptr内部使用引用计数来跟踪当前有多少个shared_ptr实例正在引用同一个对象。

为了实现这一点,我们引入了一个动态申请的int对象来进行引用计数(即下面代码中的_pcount)。

当直接使用指针进行构造时,申请一个int对象为其计数;当进行拷贝构造时,int对象++。

注意,这里不能使用静态成员变量来进行计数,因为静态成员变量统计的是shared_ptr的数量,而不是指向某一个资源的shared_ptr的数量。

删除器

智能指针析构时默认是进行delete释放资源,这也就意味着如果不是new出来的资源,交给智能指针管理,析构时就会崩溃。

智能指针支持在构造时给一个删除器,所谓删除器本质就是一个可调用对象,这个可调用对象中实现你想要的释放资源的方式,当构造智能指针时,给了定制的删除器,在智能指针析构时就会调用删除器去释放资源。

注意:unique_ptr的删除器通过在实例化模板时显式给出类型进行传递,shared_ptr只需要在构造函数的参数列表中给出可调用对象即可(lambda表达式使用更加方便)。

因为new[]经常使用,所以为了使用方便,unique_ptr和shared_ptr都特化了一份[]的版本:

unique_ptr<Date[]> up1(new Date[5]); 
shared_ptr<Date[]> sp1(new Date[5]); 

在释放资源时,会用delete[]来进行释放。 

其他注意事项

1. shared_ptr 除了支持用指向资源的指针构造,还支持 make_shared 用初始化资源对象的值直接构造:

template <class T, class... Args> 
shared_ptr<T> make_shared(Args&&... args);

 2. shared_ptr 和 unique_ptr 都支持了operator bool的类型转换,如果智能指针对象是一个空对象没有管理资源,则返回false,否则返回true,意味着我们可以直接把智能指针对象给if判断是否为空。

3. shared_ptr 和 unique_ptr 的构造函数都使用了explicit 修饰,以防止普通指针隐式类型转换成智能指针对象。

实现示例

需要注意的是我们这里实现的shared_ptr和weak_ptr都是以最简洁的方式实现的,只能满足基本的功能,这里的weak_ptr.lock等功能是无法实现的,想要实现就要把shared_ptr和weak_ptr一起改了,把引用计数拿出来放到一个单独类型,shared_ptr和weak_ptr都要存储指向这个类的对象才能实现,有兴趣可以去翻翻源代码。

namespace lbz
{template<class T>class shared_ptr{public:shared_ptr(T* ptr, function<void(T*)> del = ([](T* ptr) {delete ptr; })):_ptr(ptr), _pcount(new int(1)), _del(del){}shared_ptr(const shared_ptr<T>& sp):_ptr(sp._ptr), _pcount(sp._pcount), _del(sp._del){(*_pcount)++;}void release(){if (--(*_pcount) == 0){delete _pcount;_del(_ptr);_pcount = nullptr;_ptr = nullptr;}}~shared_ptr(){release();}shared_ptr<T>& operator=(const shared_ptr<T>& sp){// 只剩一个,且自己给自己赋值时必须这样解决if (_ptr != sp._ptr){release();_ptr = sp._ptr;_pcount = sp._pcount;_del = sp._del;++(*_pcount);}return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}T& operator[](size_t i){return _ptr[i];}T* get() const{return _ptr;}int use_count() const{return *_pcount;}private:T* _ptr;int* _pcount;function<void(T*)> _del;};
}

3. 循环引用

假如我们在双向链表中使用shared_ptr来管理资源会发生什么?

#include<memory>
using namespace std;struct ListNode
{ListNode(int val):_val(val){}int _val;std::shared_ptr<ListNode> _prev = nullptr;std::shared_ptr<ListNode> _next = nullptr;
};int main()
{std::shared_ptr<ListNode> n1(new ListNode(10));std::shared_ptr<ListNode> n2(new ListNode(20));n1->_next = n2;n2->_prev = n1;return 0;
}

n1结点不仅被n1所指向,也被n2结点的prev所指向,引用计数为2,n2同理。

当程序结束时,n1、n2的生命周期结束,对应结点的引用计数各自减一,但此时两个结点仍各有1的引用计数,不会被正常释放。

只有当n2被释放,n2->prev的生命周期结束,n1才会被释放;但n2要被释放就需要n1先被释放,使n1->next的生命周期结束。

这样就导致两个结点互相引用、相互依存,始终不会被释放。

为了解决这个问题,就引入了weak_ptr来辅助shared_ptr的使用,weak_ptr相比于shared_ptr,其不会增加被指向资源的引用计数,也不负责资源的释放,将prev和next替换为weak_ptr就可以避免循环引用。

std::weak_ptr

std::weak_ptr是一种辅助智能指针,它与shared_ptr一起使用,用于避免循环引用问题。

相比于shared_ptr,weak_ptr不增加对象的引用计数,因此它不会延长对象的生命周期。

weak_ptr不支持RAII,也不支持访问资源,所以我们看文档发现weak_ptr构造时不支持绑定到资源,只支持绑定到shared_ptr,绑定到shared_ptr时,不增加shared_ptr的引用计数,那么就可以解决上述的循环引用问题。

weak_ptr也没有重载operator* 和operator->等,因为他不参与资源管理,那么如果他绑定的shared_ptr已经释放了资源,那么他去访问资源就是很危险的。weak_ptr支持expired检查指向的资源是否过期,use_count也可获取shared_ptr的引用计数,weak_ptr想访问资源时,可以调用lock返回一个管理资源的shared_ptr,如果资源已经被释放,返回的shared_ptr是一个空对象,如果资源没有释放,则通过返回的shared_ptr访问资源是安全的。

namespace lbz
{template<class T>class weak_ptr{public:weak_ptr(){}weak_ptr(const shared_ptr<T>& sp):_ptr(sp.get()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){_ptr = sp.get();return *this;}private:T * _ptr = nullptr;};
} 

4. 智能指针使用建议

  • 优先使用unique_ptr来管理单个对象的所有权,因为它通常比shared_ptr更轻量级且更不容易产生错误。
  • 使用shared_ptr来管理共享所有权的资源,尤其是在多个对象或函数需要访问同一个资源的情况下。
  • 使用weak_ptr来避免与shared_ptr相关的循环引用问题。
  • 避免在全局作用域或静态存储持续期间使用智能指针,因为这可能会导致不必要的复杂性和潜在的资源管理问题。
  • 在可能发生异常的代码路径中使用智能指针,以确保即使在异常发生时资源也能被正确释放。
  • 当向容器或算法传递所有权时,使用std::move来将unique_ptr转换为右值引用,以便容器或算法可以接管所有权。

5. shared_ptr的线程安全问题

shared_ptr的引用计数对象在堆上,如果多个shared_ptr对象在多个线程中,进行shared_ptr的拷贝析构时会访问修改引用计数,就会存在线程安全问题,所以shared_ptr引用计数是需要加锁或者原子操作保证线程安全的。

shared_ptr指向的对象也是有线程安全的问题的,但是这个对象的线程安全问题不归shared_ptr管,它也管不了,应该有外层使用shared_ptr的人进行线程安全的控制。

下面的程序会崩溃或者A资源没释放,bit::shared_ptr引用计数从int*改成atomic<int>*就可以保证引用计数的线程安全问题,或者使用互斥锁加锁也可以。

struct AA
{int _a1 = 0;int _a2 = 0;~AA(){cout << "~AA()" << endl;}
};int main()
{bit::shared_ptr<AA> p(new AA);const size_t n = 100000;mutex mtx;auto func = [&](){for (size_t i = 0; i < n; ++i){// 这里智能指针拷贝会++计数bit::shared_ptr<AA> copy(p);{unique_lock<mutex> lk(mtx);copy->_a1++;copy->_a2++;}}};thread t1(func);thread t2(func);t1.join();t2.join();cout << p->_a1 << endl;cout << p->_a2 << endl;cout << p.use_count() << endl;return 0;
}

6. C++11和boost中智能指针的关系

Boost库是为C++语言标准库提供扩展的一些C++程序库的总称,Boost社区建立的初衷之一就是为C++的标准化工作提供可供参考的实现,Boost社区的发起人Dawes本人就是C++标准委员会的成员之一。

在Boost库的开发中,Boost社区也在这个方向上取得了丰硕的成果,C++11及之后的新语法和库有很多都是从Boost中来的。

• C++ 98 中产生了第一个智能指针auto_ptr;
• C++ boost给出了更实用的scoped_ptr / scoped_array和shared_ptr / shared_array和

  weak_ptr等;
• C++ TR1,引入了shared_ptr等,不过注意的是TR1并不是标准版;
• C++ 11,引入了unique_ptr和shared_ptr和weak_ptr。

需要注意的是unique_ptr对应boost的scoped_ptr。并且这些智能指针的实现原理是参考boost中的实现的。

7. 内存泄露

7.1 内存泄露的定义和危害

内存泄露是指程序在运行过程中动态分配的内存未能被正确释放或回收,导致这部分内存无法供其他程序或同一程序的其他部分使用。随着时间的推移,未被释放的内存会被不断累积,可能导致系统可用内存减少,进而使程序运行变慢、响应时间增加,甚至可能引发系统崩溃或资源耗尽。

7.2 如何检测内存泄露

检测内存泄露通常需要使用专门的工具,这些工具可以在程序运行时分析内存的分配和释放情况。常见的内存泄露检测工具包括Valgrind、AddressSanitizer、Visual Studio的内存诊断工具等。这些工具能够帮助开发人员识别不被释放的内存分配,并定位到代码中的具体位置。

7.3 如何避免内存泄露

避免内存泄露的关键在于遵循良好的编程习惯和系统设计原则:

  1. 严格管理内存分配和释放,确保每次动态内存分配后都有相应的释放操作。
  2. 使用智能指针和内存池等技术来自动管理内存,减少手动内存管理的错误。
  3. 进行定期的代码审查,以发现潜在的内存泄露风险点。
  4. 编写单元测试,确保内存管理的正确性。
  5. 对于不熟悉的库或框架,仔细阅读文档,了解其内存管理的细节。

相关文章:

C++笔记---智能指针

1. 什么是智能指针 1.1 RALL设计思想 RAII&#xff08;Resource Acquisition Is Initialization&#xff0c;资源获取即初始化&#xff09;是一种资源管理类的设计思想&#xff0c;广泛应用于C等支持对象导向编程的语言中。它的核心思想是将资源的管理与对象的生命周期紧密绑定…...

CentOS 7系统中更改YUM源为阿里云的镜像源

引言 更换阿里的镜像源可以带来诸多好处&#xff0c;包括提高下载速度、提升稳定性、同步更新、简化配置、节省带宽资源以及增强系统安全性等。因此&#xff0c;对于使用CentOS系统的用户来说&#xff0c;更换阿里的镜像源是一个值得考虑的选择。 1.备份yum源 mv /etc/yum.r…...

Python酷库之旅-第三方库Pandas(206)

目录 一、用法精讲 961、pandas.IntervalIndex.mid属性 961-1、语法 961-2、参数 961-3、功能 961-4、返回值 961-5、说明 961-6、用法 961-6-1、数据准备 961-6-2、代码示例 961-6-3、结果输出 962、pandas.IntervalIndex.length属性 962-1、语法 962-2、参数 …...

3.4CQU数学实验???

meshgrid 是一个用于生成网格点坐标的函数。它常用于在二维或三维空间中创建坐标网格&#xff0c;用于可视化和数据处理。 在二维情况下&#xff0c;meshgrid 函数接受两个一维数组作为输入&#xff0c;并返回两个二维数组&#xff0c;这两个数组中的元素分别表示了所有可能的…...

Linux(CentOS)开放端口/关闭端口

一、普通用户使用 sudo 操作&#xff0c;开放/关闭端口&#xff0c;80 1、检查端口是否开放 sudo firewall-cmd --zonepublic --query-port80/tcp 2、开放端口 sudo firewall-cmd --zonepublic --add-port80/tcp --permanent 3、重新加载&#xff08;开放或关闭端口后都需…...

GreenDao适配AGP8.7+

升级配置 工具版本Android StudioLadybug 2024.2.1 Path2AGP8.7.2KPG1.8.21GGP3.3.1明细 classpath "com.android.tools.build:gradle:$agp_version"classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kgp_version"classpath "org.greenrobot:g…...

【前端】Typescript从入门到进阶

以下是 TypeScript 的常用知识点总结&#xff0c;涵盖了从基础到入门的内容&#xff0c;并配有代码示例&#xff1a; 1. TypeScript 基础 1.1 安装和配置 安装 TypeScript 并初始化配置文件&#xff1a; npm install -g typescript tsc --init 1.2 基本类型 TypeScript 提供…...

在 RHEL 8 | CentOS Linux release 8.5.2111上安装 Zabbix 6

1. 备份YUM源文件 cd /etc/yum.repos.d/ mkdir bak mv C* ./bak/ wget -O /etc/yum.repos.d/CentOS-Linux-BaseOS.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo yum clean all yum makecache2. 将 SELinux 设置为宽容模式&#xff0c;如下所示。 sudo s…...

光纤HDMI线怎么连接回音壁?

第一步&#xff1a;准备HDMI线、光纤线&#xff08;TOSLINK线&#xff09;、视频源设备、回音壁 第二步&#xff1a;连接HDMI线&#xff0c;找到视频源设备上的HDMI输出口&#xff0c;将HDMI线的一端插入这个接口&#xff0c;再把HDMI线的另一端插入回音壁的HDMI输入口。注意检…...

屏幕后期处理

1、屏幕后期处理效果 屏幕后期处理效果&#xff08; Screen Post-Processing Effects&#xff09;是一种在渲染管线的最后阶段应用的视觉效果&#xff0c;允许在场景渲染完成后对最终图像进行各种调整和效果处理&#xff0c;从而增强视觉体验 常见的屏幕后期处理效果有&#x…...

K8资源之endpoint资源EP资源

1 endpoint资源概述 endpoint资源在K8S中用来表s示vc与后端 Pod 之间的连接关系的对象。当创建svc时&#xff0c;svc根据标签是否相同或svc名字是否和ep名字相同&#xff0c;把svc和ip关联上。 删除svc时&#xff0c;会自动的删除同名的ep资源。 2 ep资源和svc的关联测试 […...

微软日志丢失事件敲响安全警钟

NEWS | 事件回顾 最近&#xff0c;全球最大的软件公司之一——微软&#xff0c;遭遇了一场罕见的日志丢失危机。据报告&#xff0c;从9月2日至9月19日&#xff0c;持续长达两周的时间里&#xff0c;微软的多项核心云服务&#xff0c;包括身份验证平台Microsoft Entra、安全信息…...

Qt生成应用程序exe

1. 将工程用MinGW编译器在release模式下编译&#xff0c;生成可执行文件XXX.exe&#xff0c;新建一个文件夹如&#xff1a;F:\Setup\minGW&#xff0c;把exe文件放到这个目录下。 2. 将该编译器的bin文件添加到PATH环境变量里&#xff1a;bin文件路径为&#xff1a;D:\Qt\Qt5.…...

C#中的HttpContent、HttpClientHandle、HttpWebRequest

C#中的HttpContent 在C#中&#xff0c;HttpContent 是 System.Net.Http 命名空间下的一个类&#xff0c;它是 HttpClient 类用来发送和接收HTTP内容的基础。HttpContent 表示HTTP请求或响应的正文内容&#xff0c;并且可以序列化和反序列化数据。 HttpContent 是一个抽象类&a…...

23.网工入门篇--------介绍一下园区网典型组网架构及案例实践

园区网典型组网架构主要分为小型、中型、大型三种类型&#xff0c;以下是详细介绍及相关案例实践&#xff1a; 小型园区网&#xff1a; 架构特点&#xff1a; 用户规模&#xff1a;适用于接入用户数量较少的场景&#xff0c;一般支持几个至几十个用户。覆盖范围&#xff1a;仅限…...

QT鼠标事件

QT鼠标事件 1.概述 这篇文章介绍如何使用事件和获取事件的信号 2.创建项目 创建一个widget类型项目&#xff0c;在widget.ui文件中添加一个label控件 然后在项目名称上右键选择Add new... 添加文件&#xff0c;选择 C Class 自定义类名Mylabel&#xff0c;选择基类Base …...

Ubuntu 的 ROS 操作系统turtlebot3环境搭建

引言 本文介绍如何在Ubuntu系统中为TurtleBot3配置ROS环境&#xff0c;包括安装和配置ROS Noetic的步骤&#xff0c;为PC端控制TurtleBot3提供操作指南。 安装和配置的过程分为PC设置、系统安装、依赖安装等部分&#xff0c;并在最后进行网络配置&#xff0c;确保PC端能够顺利…...

C++笔记---异常

1. 异常的概念 1.1 异常和错误 异常通常是指在程序运行中动态出现的非正常情况&#xff0c;这些情况往往是可以预见并可以在不停止程序的情况下动态地进行处理的。 错误通常是指那些会导致程序终止的&#xff0c;无法动态处理的非正常情况。例如&#xff0c;越界访问、栈溢出…...

Python 操作数据库:读取 Clickhouse 数据存入csv文件

import pandas as pd from clickhouse_driver import Client import timeit import logging import threading from threading import Lock from queue import Queue from typing import List, Dict, Set from contextlib import contextmanager import os import time# 配置参…...

如何找到系统中bert-base-uncased默认安装位置

问题&#xff1a; 服务器中无法连接huggingface&#xff0c;故需要自己将模型文件上传 ubuntu 可以按照这个链接下载 Bert下载和使用&#xff08;以bert-base-uncased为例&#xff09; - 会自愈的哈士奇 - 博客园 里面提供了giehub里面的链接 GitHub - google-research/be…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…...

给网站添加live2d看板娘

给网站添加live2d看板娘 参考文献&#xff1a; stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下&#xff0c;文章也主…...