C++:智能指针
C++在用引用取缔掉指针的同时,模板的引入带给了指针新的发挥空间
智能指针简单的来说就是带有不同特性和内存管理的指针模板
- unique_ptr
1.不能有多个对象指向一块内存
2.对象释放时内部指针指向地址也随之释放
3.对象内数据只能通过接口更改绑定
4.对象只能接收右值或者将亡值 - shared_ptr
1.可以有多个指针对象指向一块地址
2.使用一块堆区空间维护一块地址被指向的次数
3.当指向一个地址的指针数量变为0时清除这块空间 - weak_ptr
和shared_ptr搭配使用解决了循环引用问题
首先unique_ptr实现起来其实很简单,只需要对赋值函数(=运算符重载)和拷贝构造函数等这些利用对象创建新的对象的函数做出修改即可,当然析构函数部分的释放也是要注意的。
template<typename T>
class unique_ptr{T*ptr;
public:unique_ptr(T*p=nullptr):ptr(p){}unique_ptr(unique_ptr&&other) noexcept:ptr(other.release()){other.ptr=nullptr;}unique_ptr& operator=(unique_ptr&&other) noexcept{if(other.ptr!=this->ptr){change(other.release());}return *this;}T*get()const{return ptr;}T& operator*() const{return *ptr;}T* operator->() const{return ptr;}explicit operator bool() const{return ptr!=nullptr;}~unique_ptr(){delete ptr;ptr=nullptr;}T*release(){T*tmp=this->ptr;this->ptr=nullptr;return tmp;}void change(T*cur=nullptr){if(cur!=ptr){delete ptr;ptr=cur;}}unique_ptr(const unique_ptr&)=delete;unique_ptr& operator=(const unique_ptr&)=delete;
};
然后看shared_ptr它的话要比unique_ptr要自由的多实现起来也很简单,只需要多一步计数操作即可。
template<typename T>
class shared_ptr{T*ptr;int* cnt;
public:shared_ptr(T*p=nullptr):ptr(p),cnt(new int(1)){}shared_ptr(const shared_ptr&other) noexcept:ptr(other.ptr),cnt(other.cnt){(*cnt)++;}shared_ptr& operator=(const shared_ptr&other) noexcept{if(this!=&other){release();this->ptr=other.ptr;this->cnt=other.cnt;(*cnt)++;}return *this;}T*get()const{return ptr;}T& operator*() const{return *ptr;}T* operator->() const{return ptr;}explicit operator bool() const{return ptr!=nullptr;}~unique_ptr(){release();}void release(){if(cnt&&--(*cnt)==0){delete cnt;delete ptr;}ptr=nullptr;cnt=nullptr;}
};
但是注意shared_ptr的计数可能会带来一个问题:循环引用
看下面代码其实很好理解,就是循环指向造成计数到不了0从而释放不了对象。
class B;
class A{
public:shared_ptr<B>aptr;
};
class B{
public:shared_ptr<A>bptr;
};
int main(){shared_ptr<A>a=new A;shared_ptr<B>b=new B;a->aptr=b;b->bptr=a;
}
解决方式:引入了weak_ptr搭配shared_ptr使用,weak_ptr是对对象的一种弱引用,它不会增加对象的use_count,weak_ptr和shared_ptr可以相互转化,shared_ptr可以直接赋值给weak_ptr,weak_ptr也可以通过调用lock函数来获得shared_ptr。
- weak_ptr指针通常不单独使用,只能和 shared_ptr 类型指针搭配使用。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象也还是会被释放。
- weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象,典型的用法是调用其lock函数来获得shared_ptr示例,进而访问原始对象。
- 需要注意weak_ptr不维护资源的释放,因为需要避免资源被释放两次,因此weak_ptr常用在为生命周期一致的shared_ptr赋值
template <typename T>
class MySharedPtr;template <typename T>
class MyWeakPtr;template <typename T>
class MySharedPtr {
private:T* ptr;int* refCount;int* weakCount;public:explicit MySharedPtr(T* p = nullptr) : ptr(p), refCount(new int(1)), weakCount(new int(0)) {}MySharedPtr(const MySharedPtr& other) : ptr(other.ptr), refCount(other.refCount), weakCount(other.weakCount) {(*refCount)++;}~MySharedPtr() {release();}int use_count() const {return (refCount ? *refCount : 0);}T* get() const {return ptr;}T& operator*() const {return *ptr;}T* operator->() const {return ptr;}MyWeakPtr<T> weak_ptr() {(*weakCount)++;return MyWeakPtr<T>(this->ptr, this->refCount, this->weakCount);}MySharedPtr& operator=(const MySharedPtr& other) {if (this != &other) {release();ptr = other.ptr;refCount = other.refCount;weakCount = other.weakCount;(*refCount)++;}return *this;}private:void release() {if (refCount) {(*refCount)--;if (*refCount == 0) {delete ptr;delete refCount;if (*weakCount == 0) {delete weakCount;}}}}friend class MyWeakPtr<T>;
};template <typename T>
class MyWeakPtr {
private:T* ptr;int* refCount;int* weakCount;public:MyWeakPtr() : ptr(nullptr), refCount(nullptr), weakCount(nullptr) {}MyWeakPtr(T* p, int* rc, int* wc) : ptr(p), refCount(rc), weakCount(wc) {}MyWeakPtr(const MyWeakPtr& other) : ptr(other.ptr), refCount(other.refCount), weakCount(other.weakCount) {(*weakCount)++;}~MyWeakPtr() {release();}MySharedPtr<T> lock() {if (expired()) {return MySharedPtr<T>();}(*refCount)++;return MySharedPtr<T>(ptr, refCount, weakCount);}MyWeakPtr& operator=(const MyWeakPtr& other) {if (this != &other) {release();ptr = other.ptr;refCount = other.refCount;weakCount = other.weakCount;(*weakCount)++;}return *this;}bool expired() const {return (refCount == nullptr || *refCount == 0);}
private:void release() {if (weakCount) {(*weakCount)--;if (*weakCount == 0) {delete weakCount;}}}
};
shared_ptr和weak_ptr可以互相构造,看下面的代码就知道它们是如何解决循环引用的情况
class B;
class A{
public:MYShared_Ptr<B>aptr;
};
class B{
public:MYWeak_Ptr<A>bptr;
};
int main(){MYShared_Ptr<A>a=new A;MYShared_Ptr<B>b=new B;a->aptr=b.lock();b->bptr=a;
}
简单的来说就是通过两个可以互相转换的类型避免产生同种类型的环,对不同类型的环它们释放的时候互不影响对方的计数所以可以正常释放。
相关文章:
C++:智能指针
C在用引用取缔掉指针的同时,模板的引入带给了指针新的发挥空间 智能指针简单的来说就是带有不同特性和内存管理的指针模板 unique_ptr 1.不能有多个对象指向一块内存 2.对象释放时内部指针指向地址也随之释放 3.对象内数据只能通过接口更改绑定 4.对象只能接收右值…...

用户界面(UI)、用户体验(UE)和用户体验(UX)的差异
对一个应用程序而言,UX/UE (user experience) 设计和 UI (user interface) 设计非常重要。UX设计包括可视化布局、信息结构、可用性、图形、互动等多个方面。UI设计也属于UX范畴。正是因为三者在一定程度上具有重叠的工作内容,很多从业多年的设计师都分不…...

react 之 UseReducer
UseReducer作用: 让 React 管理多个相对关联的状态数据 import { useReducer } from react// 1. 定义reducer函数,根据不同的action返回不同的新状态 function reducer(state, action) {switch (action.type) {case INC:return state 1case DEC:return state - 1de…...
C++:this隐藏参数
你是否有一个问题:C中成员函数中究竟是如何访问成员变量的? 其实了解后回答起来这个问题很简单,通过一个不受限的隐藏参数this,this是类的指针,通过它可以访问到类内的各种成员。 明白了这个问题就很好理解ÿ…...

MySQL事务原理-相关日志
文章目录 前言一、什么是事务?1.1 事务概念1.2 事务的四大特性1.3 事务的隔离级别 二、实现原理2.1 TODO2.2 TODO 前言 事务是由MySQL的引擎来实现的,通过show engines命令查看MySQL存储引擎类别,观察只有InnoDB存储引擎支持事务。 一、什么…...
内核Oops的几种定位方法
反汇编 报错信息 [ 1.826455] ------------[ cut here ]------------ [ 1.831091] Kernel BUG at c011fef0 [verbose debug info unavailable] [ 1.837344] Internal error: Oops - BUG: 0 [#1] PREEMPT THUMB2 [ 1.843108] Modules linked in: [ 1.846158] C…...

外包干了10个月,技术退步明显.......
先说一下自己的情况,大专生,18年通过校招进入武汉某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…...
2024美赛C完整思路
首先,题目明确表示可以自行选择额外的玩家信息或其他数据。因此最好找一些其他选手的数据以扩大数据集,与其他选题人作出数据集上的区分。大数据集可以帮助后续的建模实验更准确。 第一问本质就是开发一个评价模型,主要针对运动员得分的时刻…...

Backtrader 文档学习- Broker - Cheat-On-Open
Backtrader 文档学习- Broker - Cheat-On-Open 1.概述 V1.9.44.116增加了Cheat On Open的支持。对于全押的人来说,这似乎是一个必需的功能,用bar的收盘价后进行计算,希望与开盘价相匹配。 当开盘价差距(上涨或下跌,取…...
基于微信浙江杭州某停车场车位预约小程序系统设计与实现 研究背景和意义、国内外现状
博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程ÿ…...

编程流程图
对于复杂流程,我做开发之前一般会 先画一下流程图。特别是多个部门有交叉的情况下: processOn: 这个是我之前 一直的选择,他可以画上面的这些,流程图,网页操作,但是他不是免费的,查过…...
2024年1月29日-2月4日(全面进行+收集虚幻商城免费资源)
从上周发现,一轮轮推就行,每轮多个时间片,每个时间片一门。周一到周五一轮,周六日多轮(比如上下午各一轮)。 周一: 7:09–9:20卫星导航定位(p3)&a…...

【python接口自动化】- 正则用例参数化
🔥 交流讨论:欢迎加入我们一起学习! 🔥 资源分享:耗时200小时精选的「软件测试」资料包 🔥 教程推荐:火遍全网的《软件测试》教程 📢欢迎点赞 👍 收藏 ⭐留言 …...
Java中的四种线程池详解及使用场景
前言 在Java并发编程中,JDK提供了一套强大的线程池工具类java.util.concurrent.ThreadPoolExecutor以及它的四个便捷工厂方法,这四种线程池分别对应不同的使用场景和特性。下面将详细介绍每种线程池的创建方式、工作原理以及适用场景。 1. CachedThrea…...

Google Chrome 常用的几个参数
1 右键--Google Chrome--属性--目标 参数作用--disable-infobars此计算机将不会再收到 Google Chrome 更新,因为 Windows XP 和 Windows Vista 不再受支持。适用于 xp、2003 的 49.x.x.x 版本。示例1--ingore-certificate-errors忽略证书错误--disable-background-…...

Keil软件某些汉字输出乱码,0xFD问题,51单片机
1. 问题 keil软件输入某些汉字的时候会输出乱码,例如:升、 数 2. 原因 keil软件会忽略0xFD。 升的GB2312编码为 0xc9fd,keil解析为0xc9数的GB2312编码为 0xcafd,keil解析为0xca 关于Keil软件中0xFD问题的说明 3. 解决方案1 …...

自然语言开发AI应用,利用云雀大模型打造自己的专属AI机器人
如今,大模型层出不穷,这为自然语言处理、计算机视觉、语音识别和其他领域的人工智能任务带来了重大的突破和进展。大模型通常指那些参数量庞大、层数深、拥有巨大的计算能力和数据训练集的模型。 但不能不承认的是,普通人使用大模型还是有一…...
Android中 Gradle与 AGP 版本对应关系表
Android Gradle Plugin Version版本Gradle Version版本1.0.0 - 1.1.32.2.1 - 2.31.2.0 - 1.3.12.2.1 - 2.91.5.02.2.1 - 2.132.0.0 - 2.1.22.10 - 2.132.1.3 - 2.2.32.14.12.3.03.33.0.04.13.1.04.43.2.0 - 3.2.14.63.3.0 - 3.3.34.10.13.4.0 - 3.4.35.1.13.5.0 - 3.5.45.4.13.…...

Linux基础知识合集
整理了一下学习的一些关于Linux的一些基础知识,同学们也可以通过公众号菜单栏查看! 一、基础知识 Linux基础知识 Linux命令行基础学习 Linux用户与组概念初识 Linux文件与目录权限基础 Linux中文件内容的查看 Linux系统之计划任务管理 二、服务器管理 Vm…...

跟着pink老师前端入门教程-day13
品优购案例 一、品优购项目规划 1. 品优购项目整体介绍 项目名称:品优购 项目描述:品优购是一个电商网站,我们要完成 PC 端首页、列表页、注册页面的制作 2. 品优购项目学习目的 1. 电商类网站比较综合,里面需要大量的布…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...

代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...

【堆垛策略】设计方法
堆垛策略的设计是积木堆叠系统的核心,直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法,涵盖基础规则、优化算法和容错机制: 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则: 大尺寸/重量积木在下…...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...

C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...