C++——智能指针1
目录
RAII
auto_ptr模拟实现
智能指针拷贝问题
唯一指针
完整代码
循环引用
weak_ptr模拟实现
定制删除器
内存泄漏
RAII
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内
存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在
对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做
法有两大好处:
不需要显式地释放资源。
采用这种方式,对象所需的资源在其生命期内始终保持有效.
此时释放了资源

抛异常后没有释放资源

提供一个类 ,在该类的对象构造时获取资源,析构时释放资源
#include<iostream>
using namespace std;
//利用RAII设计的释放delete资源的类
template<class T>
class SmartPtr
{
public:SmartPtr(T* Ptr)//在构造的时候把资源给某个对象:_ptr(Ptr){}~SmartPtr()//析构的时候把资源进行释放{delete _ptr;cout << "资源释放 " <<"delete:" <<_ptr<< endl;}
private:T* _ptr;
};
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;SmartPtr<int> sp1(p1);SmartPtr<int> sp2(p2);cout << div() << endl;
}
int main()
{try{Func();}catch (exception& e){cout << e.what() << endl;}return 0;
}
抛异常也能进行正常的资源释放

上述的SmartPtr还不能将其称为智能指针,因为它还不具有指针的行为。指针可以解引用,也可
以通过->去访问所指空间中的内容,因此:AutoPtr模板类中还得需要将* 、->重载下,才可让其
像指针一样去使用。

总结一下智能指针的原理:
1. RAII特性
2. 重载operator*和opertaor->,具有像指针一样的行为。
库里面的智能指针有很多,如auto——ptr

auto_ptr模拟实现
template<class T>class auto_ptr{public:auto_ptr(T* ptr = nullptr): _ptr(ptr){}auto_ptr(auto_ptr<T>& ap):_ptr(ap._ptr){ap._ptr = nullptr;}// ap1 = ap2;auto_ptr<T>& operator=(auto_ptr<T>& ap){if (this != &ap){if (_ptr){cout << "Delete:" << _ptr << endl;delete _ptr;}_ptr = ap._ptr;ap._ptr = nullptr;}return *this;}~auto_ptr(){if (_ptr){cout << "Delete:" << _ptr << endl;delete _ptr;}}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};
智能指针拷贝问题
对上面我们写的类,创建俩个对象直接进行拷贝,程序会崩溃

这是因为对空间A析构了俩次,我们虽然没写拷贝构造函数但是这里_ptr是内置类型,对内置类型完成了值拷贝,然后在析构的时候对这块空间析构了俩次,导致程序直接崩溃

库里面的没有崩溃

auto_ptr的拷贝构造在拷贝的时候把资源进行了转移,ap1把资源直接转给了ap2,相当于把ap1进行了剪切,ap1被置空了


解决方案:
深拷贝:这里不能用深拷贝,因为违背了功能需求 ,智能指针我们不知道要拷贝多少,拷贝的资源有多大。智能指针只是帮助我们进行托管,像指针一样。这里需要的就是浅拷贝
唯一指针
禁用了拷贝构造和赋值 ,其它功能都正常


template<class T>
class unique_ptr
{
private:// 防拷贝 C++98// 只声明不实现 //unique_ptr(unique_ptr<T>& ap);//unique_ptr<T>& operator=(unique_ptr<T>& ap);
public:unique_ptr(T* ptr = nullptr): _ptr(ptr){}// 防拷贝 C++11unique_ptr(unique_ptr<T>& ap) = delete;//拷贝构造是默认成员函数unique_ptr<T>& operator=(unique_ptr<T>& ap) = delete;~unique_ptr(){if (_ptr){cout << "Delete:" << _ptr << endl;delete _ptr;}}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;
};
C++98只声明,不实现

而且必须的私有,不然会报错


私有化后,赋值和拷贝就不能使用了


shared_ptr(可以拷贝)
增加了引用计数,表示有n个对象管理这块资源


这里的计数不能用静态的,
析构的时候--计数,减到0了就释放空间

出问题


这里空间被释放了俩次 ,还有一次未被释放。
注释掉后面俩个,也被释放了俩次


本应是这样,静态成员变量是所有类共享的

sp4 来了之后,计数又变为了1,因为类型不一样,由于这些计数是共享的导致sp1,sp2,sp3的计数也变成了1

所以我们在这里采用指针,


一个资源,配一个计数,多个智能指针对象共管。
如果用静态计数,静态计数对象所有资源都只有一个计数, 因为静态成员属于整个类,属于类的所有对象。
shared_ptr模拟实现
operator=
void Release(){if (--(*_pCount) == 0){cout << "Delete:" << _ptr << endl;delete _ptr;delete _pCount;}}shared_ptr<T>& operator=(const shared_ptr<T>& sp){//if (this == &sp)if (_ptr == sp._ptr){return *this;}// 减减被赋值对象的计数,如果是最后一个对象,要释放资源/*if (--(*_pCount) == 0){delete _ptr;delete _pCount;}*/Release();// 共管新资源,++计数_ptr = sp._ptr;_pCount = sp._pCount;(*_pCount)++;return *this;}
如果没有中间的Realse,sp1指向sp5之后,图中最上面那块空间计数还是3,如果是0就直接释放空间
完整代码
template<class T>
class shared_ptr
{
public:shared_ptr(T* ptr = nullptr): _ptr(ptr), _pCount(new int(1)){}void Release(){if (--(*_pCount) == 0){cout << "Delete:" << _ptr << endl;delete _ptr;delete _pCount;}}~shared_ptr(){Release();}// sp1(sp2)shared_ptr(const shared_ptr<T>& sp): _ptr(sp._ptr), _pCount(sp._pCount)//把计数也要给拷贝,拷贝完之后++即可{(*_pCount)++;}shared_ptr<T>& operator=(const shared_ptr<T>& sp){//if (this == &sp)if (_ptr == sp._ptr){return *this;}// 减减被赋值对象的计数,如果是最后一个对象,要释放资源/*if (--(*_pCount) == 0){delete _ptr;delete _pCount;}*/Release();// 共管新资源,++计数_ptr = sp._ptr;_pCount = sp._pCount;(*_pCount)++;return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;// 引用计数int* _pCount;
};
循环引用
C++98不支持n2这种方式,必须得和n1一样,不允许隐式类型转换


此时会报错,因为n2是智能指针,next是原生指针

将next改成智能指针后,程序可以正常运行



n2->prve指向n1

此时又不释放空间



这是因为函数结束得时候,n2先析构,n1后析构

next析构右边就释放(delete),prev析构左边就释放(delete),_next在左边,左边的节点被delete时调用析构函数,_next作为成员才会析构,而要释放左边的节点,_prev就得先释放,释放_prev就要先释放右边的节点,右边的节点是否释放又取决于_next,所以俩边互相克制
用weak_ptr就能解决这种问题,这不是常规的智能指针,没有RAII,不支持直接管理资源,wak_ptr主要用于shared_ptr构造,用来解决shared_ptr的循环引用问题。

_next和_prev时weak_ptr时,他不参与释放资源管理,可以访问和修改到资源,但是不增加计数,不存在循环引用的问题
shared_ptr中有一个use_count专门用来查看计数


这里可以看到赋值前后的计数没有变
weak_ptr模拟实现
weak_ptr是辅助型智能指针,解决配合shared_ptr循环引用问题



namespace bit
{template<class T>class shared_ptr{public:shared_ptr(T* ptr = nullptr): _ptr(ptr), _pCount(new int(1)){}void Release(){if (--(*_pCount) == 0){cout << "Delete:" << _ptr << endl;delete _ptr;delete _pCount;}}~shared_ptr(){Release();}// sp1(sp2)shared_ptr(const shared_ptr<T>& sp): _ptr(sp._ptr), _pCount(sp._pCount)//把计数也要给拷贝,拷贝完之后++即可{(*_pCount)++;}shared_ptr<T>& operator=(const shared_ptr<T>& sp){//if (this == &sp)if (_ptr == sp._ptr){return *this;}// 减减被赋值对象的计数,如果是最后一个对象,要释放资源/*if (--(*_pCount) == 0){delete _ptr;delete _pCount;}*/Release();// 共管新资源,++计数_ptr = sp._ptr;_pCount = sp._pCount;(*_pCount)++;return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}int use_count(){return *_pCount;}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(const weak_ptr<T>& sp)//俩个拷贝构造函数:_ptr(sp._ptr){}//不写析构,不释放资源T& operator*(){return *_ptr;}T* operator->(){return _ptr;}weak_ptr<T>& operator=(const shared_ptr<T>& sp){//这里赋值不需要考虑释放资源,因为weak_ptr不参与管理资源_ptr = sp.get();return *this;}private:T* _ptr;};
}
struct Node
{int _val;bit::shared_ptr<Node> _next;bit::shared_ptr<Node> _prev;~Node(){cout << "~Node" << endl;}
};

没有增加引用计数,没有打印delete
定制删除器


程序直接崩掉,因为没有匹配使用
当换成内置类型后,程序正常运行


当屏蔽掉自定义类型的析构函数时,程序不会报错,当析构函数存在时,函数会报错

这些问题跟new实现相关,new底层调用malloc,delete底层调用free, vs平台上new内置类型[5],如new int[5],用delete释放没问题,但是在其它平台上可能会出问题,对于自定义类型要调构造函数和析构函数。


如果不写析构函数,编译器就会进行优化,对析构函数就不再调用,就只剩free,所以不会报错,当析构函数写了,就会调用,我们new Node[5],而delete却不知道要调用多少次析构函数,delete不知道[]中的数字,语法规定delete使用时是delete[],所以delete不知道要析构多少次。
vs下如果要开60byte空间,会多给4byte,总共开64byte,这4个byte用来记录次数
当释放的时候把ptr强转为char*然后-4,ptr此时指向记录次数这块空间,然后转为int*,再解引用就可获得析构次数,之后开始调用析构函数,free的时候,free的是ptr-4这个位置就是开头的位置。

shared_ptr的定制删除器 ,del可以是仿函数

unique_ptr也支持



跟C++11相结合


unique必须跟传模板参数一样,传过去


模仿shared_ptr这种方式也不行
需要这样传参


当我们自己要模拟实现定制删除器时,我们上面写的shared_ptr和unique_ptr都无法支持定制删除器。
在类模板增加一个参数D,当引用计数--后等于0时, 下面是调用D operator(),根据D重载()的内容,对ptr进行处理

写一个删除器

shared_ptr定制删除器模拟实现
template<class T>
struct Delete
{void operator()(T* ptr){cout << "delete:" << ptr << endl;delete ptr;}
};template<class T, class D = Delete<T>>
class shared_ptr
{
public:shared_ptr(T* ptr = nullptr): _ptr(ptr), _pCount(new int(1)){}void Release(){if (--(*_pCount) == 0){//cout << "Delete:" << _ptr << endl;//delete _ptr;//D del;//del(_ptr);D()(_ptr);delete _pCount;}}~shared_ptr(){Release();}// sp1(sp2)shared_ptr(const shared_ptr<T>& sp): _ptr(sp._ptr), _pCount(sp._pCount){(*_pCount)++;}shared_ptr<T>& operator=(const shared_ptr<T>& sp){//if (this == &sp)if (_ptr == sp._ptr){return *this;}// 减减被赋值对象的计数,如果是最后一个对象,要释放资源/*if (--(*_pCount) == 0){delete _ptr;delete _pCount;}*/Release();// 共管新资源,++计数_ptr = sp._ptr;_pCount = sp._pCount;(*_pCount)++;return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}int use_count(){return *_pCount;}T* get() const{return _ptr;}private:T* _ptr;// 引用计数int* _pCount;
};

这里必须显示的传第二个模板参数,不然delete次数会匹配不上,程序会崩溃


内存泄漏
C/C++程序中一般我们关心两种方面的内存泄漏:
堆内存泄漏(Heap leak)
堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一
块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分
内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
系统资源泄漏
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放
掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
如何检测内存泄漏(了解)
在linux下内存泄漏检测:(39条消息) Linux下几款C++程序中的内存泄露检查工具_CHENG Jian的博客-CSDN博客_linux c++ 内存泄露 检测
在windows下使用第三方工具:(39条消息) VS编程内存泄漏:VLD(Visual LeakDetector)内存泄露库_波波在学习的博客-CSDN博客
其他工具:内存泄露检测工具比较 - 默默淡然 - 博客园 (cnblogs.com)
内存泄漏是指针丢了还是内存丢了?
答:指针丢了,通过指针去释放指针,内存本身不存在丢失,当进程正常结束,内存也会释放,要避免僵尸进程和长期运行的程序的内存泄漏。
如何避免内存泄漏
1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:
这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智
能指针来管理才有保证。
2. 采用RAII思想或者智能指针来管理资源。
3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。
总结一下:
内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄
漏检测工具。
相关文章:
C++——智能指针1
目录 RAII auto_ptr模拟实现 智能指针拷贝问题 唯一指针 shared_ptr(可以拷贝) shared_ptr模拟实现 完整代码 循环引用 weak_ptr模拟实现 定制删除器 shared_ptr定制删除器模拟实现 内存泄漏 RAII RAII(Resource Acquisit…...
[数据集][VOC][目标检测]翻越栏杆翻越防护栏数据集目标检测可用yolo训练-1035张介绍
数据集格式:Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件,仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数):1035 标注数量(xml文件个数):1035 标注类别数:2 标注类别名称:["fylg","…...
深度学习 | BN层原理浅谈
深度学习 | BN层原理浅谈 文章目录深度学习 | BN层原理浅谈一. 背景二. BN层作用三. 计算原理四. 注意事项为什么BN层一般用在线性层和卷积层的后面,而不是放在激活函数后为什么BN能抑制过拟合(有争议)一. 背景 神经网络在训练时,由于内存限制࿰…...
每日面试题
2022/12/15 如何实现一个IOC容器 1、配置文件配置包扫描路径 2、递归包扫描获取.class文件 3、反射、确定需要交给lOC管理的类4、对需要注入的类进行依赖注入 配置文件中指定需要扫描的包路径 定义一些注解,分别表示访问控制层、业务服务层、数据持久层、依赖注…...
将IDEA的项目托管到gitee
目录1. 在gitee上创建仓库2. 本地创建仓库目录3. 将项目添加到缓冲区4. 将缓冲区的项目添加到本地仓库5. 将本地仓库的项目上传到gitee6. 遇到的问题6.1 问题描述6.2 解决方法7. 相关图示与补充8. 相关参考1. 在gitee上创建仓库 2. 本地创建仓库目录 在IDEA中选择创建 Git 仓…...
父类子类静态代码块、构造代码块、构造方法执行顺序
github:https://github.com/nocoders/java-everything.git 名词解释 静态代码块:java中使用static关键字修饰的代码块,每个代码块只会执行一次,JVM加载类时会执行静态代码块中的代码,静态代码块先于主方法执行。构造代码块&#…...
【C++】开散列实现unordered_map与unordered_set的封装
本文主要介绍unordered_map与unordered_set的封装,此次封装主要用上文所说到的开散列,通过开散列的一些改造来实现unordered_map与unordered_set的封装 文章目录一、模板参数二、string的特化三、正向迭代器四、构造与析构五、[]的实现六、unordered_map的实现七、u…...
华为OD机试真题Python实现【删除指定目录】真题+解题思路+代码(20222023)
删除指定目录 题目 某文件系统中有 N 个目录, 每个目录都一个独一无二的 ID。 每个目录只有一个付目录, 但每个目录下可以有零个或多个子目录, 目录结构呈树状结构。 假设 根目录的 ID 为0,且根目录没有父目录 ID 用唯一的正整数表示,并统一编号 现给定目录 ID 和其付目…...
CSS选择器大全(上)
基础选择器: id选择器:#id{} 类选择器: .class{} 标签选择器: h1{} 复合选择器: 交集选择器:作用:选中同时符合多个条件的元素 语法:选择器1选择器2选择器3选择器n{} 注意ÿ…...
JavaScript 俄罗斯方块 - setTimeout和rAF
本节内容需要有些基础知识,如进程和线程,队列数据结构 一、setTimeout和setInterval 只要使用过JavaScript的朋友,对setTimeout和setInterval应该不会默生,如果光说怎样去使用这个API,并不难,无非就是隔多少毫秒再执行某个函数,把变化的内容封装在函数中,就可以制作出动…...
LeetCode:构造最大二叉树;使用中序和后序数组构造二叉树;使用前序和中序数组遍历二叉树。
构造二叉树最好都是使用前序遍历;中左右的顺序。 654. 最大二叉树 中等 636 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建…...
nodejs实现jwt
jwt是json web token的简称,本文介绍它的原理,最后后端用nodejs自己实现如何为客户端生成令牌token和校验token 1.为什么需要会话管理 我们用nodejs为前端或者其他服务提供resful接口时,http协议他是一个无状态的协议,有时候我们…...
结构体占用内存大小如何确定?-->结构体字节对齐 | C语言
目录 一、什么是结构体 二、为什么需要结构体 三、结构体的字节对齐 3.1、示例1 3.2、示例2 3.3、示例3 3.4、示例4 3.5、示例5 四、结构体字节对齐总结 一、什么是结构体 结构体是将不同类型的数据按照一定的功能需 求进行整体封装,封装的数据类型与大小均…...
Vue和Uniapp:优缺点比较
Vue和Uniapp是两个流行的前端框架,都是用于开发跨平台应用程序的工具。虽然两者都有很多相似之处,但它们也有一些不同之处,这些不同之处可以影响你的选择。下面将对Vue和Uniapp的优缺点进行比较和分析,以帮助你做出更明智的决策。…...
AMBA-AXI(二)AXI的序,保序与乱序
💡Note:本文是根据AXI协议IHI0022F_b_amba_axi_protocol_spec.pdf(issue F)整理的。主要是分享AXI3.0和4.0部分。如果内容有问题请大家在评论区中指出,有补充或者疑问也可以发在评论区,互相学习ὤ…...
APIs and Open Interface--非工单领、发料(含调拨)
表名 MTL_TRANSACTIONS_INTERFACEMTL_TRANSACTION_LOTS_INTERFACE序列 MTL_MATERIAL_TRANSACTIONS_S.NEXTVALAPIs INV_TXN_MANAGER_PUB.PROCESS_TRANSACTIONS案例 杂发/杂收(代码)Declare v_user_id number : fnd_global.user_id; v_login_id number …...
互联网医院系统软件开发|互联网医院管理系统开发的好处
互联网医院一直是现在的热门行业,很多的医院已经开发了互联网医院,并且已经在良好的运行中,而有一些医院和企业正在开发中,或者打算开发互联网医院系统,其实这些企业和医院还是很有远见的,因为他们知道并了…...
2.单例模式
基本概念 单例模式:保证一个类只有一个实例,并提供一个访问该实例的全局访问点 常见应用场景 读取配置文件的类一般设计为单例模式网站计数器应用程序的日志应用,因为共享日志文件一直处于打开状态,只能有一个实例去操作Spring…...
【保姆级】Java后端查询数据库结果导出xlsx文件+打印xlsx表格
目录前言一、需求一:数据库查询的数据导出成Excel表格1.1 Vue前端实现导出按钮点击事件1.2 后端根据数据库查询结果生成xlsx文件二、需求二:对生成的xlsx文件调用打印机打印2.1 Vue前端实现按钮事件2.2 后端实现打印前言 最近在弄一个需求,需…...
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)
文章目录1 JDBC(Java Database Connectivity)1.1 什么是 JDBC?1.2 JDBC 核心思想2 JDBC开发步骤【重点】2.0 环境准备2.1 注册数据库驱动2.2 获取数据库的连接2.3 获取数据库操作对象Statement2.4 通过Statement对象执行SQL语句2.5 处理返回结…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
