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

智能指针解读(2)

前面一篇文章,我讲解了智能指针的原理,并实现了一个简单的智能指针。为了加深对智能指针的理解,在这篇文章中,我把C++中的几个智能指针讲解下:auto_ptr, unique_ptr, shared_ptr, weak_ptr。

1、auto_ptr

前面的文章我们把smart_ptr的拷贝构造函数、赋值运算符都禁掉了。auto_ptr在拷贝构造函数和赋值运算符里是怎么处理的呢?它会把原来的指针赋为nullptr。

template<class T>
class auto_ptr {
public:auto_ptr(T* _ptr) : ptr(_ptr) {}auto_ptr(auto_ptr& _ap) : ptr(_ap.ptr) {_ap.ptr = nullptr;}auto_ptr<T>& operator = (auto_ptr<T>& _ap) {if (ptr != _ap.ptr) {ptr = _ap.ptr;_ap.ptr = nullptr;}return *this;}~auto_ptr() {delete ptr;ptr = nullptr;}T& operator * () {return *ptr;}T* operator -> () {return ptr;}
private:T* ptr;
};

3、unique_ptr

unique_ptr是c++11版本库中提供的智能指针,它直接将拷贝构造函数和赋值重载函数给禁用掉。所以unique_ptr只能move,不能赋值。

4、shared_ptr

shared_ptr允许多个智能指针可以指向同一块资源,并且能够保证共享的资源只会被释放一次。
shared_ptr采用的是引用计数原理来实现多个shared_ptr对象之间共享资源:
(1)引用计数用来记录该资源被几个对象共享。
(2)当一个shared_ptr对象被销毁时(调用析构函数),析构函数内就会将该计数减1。
(3)如果引用计数减为0后,则表示自己是最后一个使用该资源的shared_ptr对象,必须释放资源。
(4)如果引用计数不是0,就说明自己还有其他对象在使用,则不能释放该资源。

在使用shared_ptr时,要注意不要让2个shared_ptr指向同一个原始指针,比如:

A* p = new A(10);
shared_ptr<A> sp1(p), sp2(p);

sp1 和 sp2 并不会共享同一个对 p 的引用计数,而是各自将对 p 的引用计数都记为 1(sp2 无法知道 p 已经被 sp1 托管过)。这样,当 sp1 消亡时要析构 p,sp2 消亡时要再次析构 p,这会导致程序崩溃。

5、weak_ptr

weak_ptr类的对象可以指向shared_ptr,但不会改变shared_ptr的引用计数。一旦最后一个shared_ptr被销毁时,对象就会被释放。
weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象,典型的用法是调用其lock函数来获得shared_ptr示例,进而访问原始对象。

我们来看一个shared_ptr交叉引用的例子:

class B;
class A
{
public:shared_ptr<B> sp;~A(){cout << "~A"<<endl;}
};
class B
{
public:shared_ptr<A> sp;~B(){cout << "~B"<<endl;}
};void fun() {shared_ptr<B> pb(new B());shared_ptr<A> pa(new A());pb->sp = pa;cout << "pb.use_count " << pb.use_count() << endl;//1cout << "pa.use_count " << pa.use_count() << endl;//2pa->sp = pb;cout << "pb.use_count " << pb.use_count() << endl;//2cout << "pa.use_count " << pa.use_count() << endl;//2//并没有输出 ~A, ~B,也就是class B;
class A
{
public:shared_ptr<B> sp;~A(){cout << "~A"<<endl;}
};
class B
{
public:shared_ptr<A> sp;~B(){cout << "~B"<<endl;}
};void fun() {shared_ptr<B> pb(new B());shared_ptr<A> pa(new A());pb->sp = pa;cout << "pb.use_count " << pb.use_count() << endl;//1cout << "pa.use_count " << pa.use_count() << endl;//2pa->sp = pb;cout << "pb.use_count " << pb.use_count() << endl;//2cout << "pa.use_count " << pa.use_count() << endl;//2//没有输出~A, ~B。也就是没有调用A和B的析构函数。
}

怎么去避免这种交叉引用呢?这就需要使用weak_ptr:把A中的shared_ptr<B> sp改为weak_ptr<B> sp_weak,这样传递时不会增加sp引用计数use_count()的值,所以最终能够使A、B资源正常释放:

class B;
class A
{
public://shared_ptr<B> sp;weak_ptr<B> sp_weak;~A(){cout << "~A"<<endl;}
};
class B
{
public:shared_ptr<A> sp;~B(){cout << "~B"<<endl;}
};void fun() {shared_ptr<B> pb(new B());shared_ptr<A> pa(new A());pb->sp = pa;cout << "pb.use_count " << pb.use_count() << endl;//1cout << "pa.use_count " << pa.use_count() << endl;//2//pa->sp = pb;pa->sp_weak = pb;cout << "pb.use_count " << pb.use_count() << endl;//1cout << "pa.use_count " << pa.use_count() << endl;//2shared_ptr<B> pa2 = pa->sp_weak.lock();}

相关文章:

智能指针解读(2)

前面一篇文章&#xff0c;我讲解了智能指针的原理&#xff0c;并实现了一个简单的智能指针。为了加深对智能指针的理解&#xff0c;在这篇文章中&#xff0c;我把C中的几个智能指针讲解下&#xff1a;auto_ptr, unique_ptr, shared_ptr, weak_ptr。 1、auto_ptr 前面的文章我…...

javax.servlet.ServletException: 非法访问资源(/j_spring_security_check)

部署的web页面登录访问报错500状态码。 开发出于安全考虑引入了refer白名单&#xff0c;但是没有通知交付人员。 需要将浏览器访问的url加入到refer白名单中&#xff0c;问题解决。 filterconfig.xml <refer-domain> <value>http://localhost</value> …...

自定义事件的使用

绑定自定义事件 在Vue.js中&#xff0c;你可以使用自定义事件来实现组件之间的通信。自定义事件允许你在一个组件中触发事件&#xff0c;并在另一个组件中监听并响应该事件。以下是自定义事件的使用方法&#xff1a; 定义一个触发事件的组件&#xff1a; <template>&l…...

buuctf-[ASIS 2019] Unicorn shop

打开网站 先去看看源代码8 前面一大坨绿的&#xff0c;肯定是提示&#xff0c;都是英文有点无语 试了试打开admin.password看看有没有东西 nice毫无变化 然后我就看了看这个页面&#xff0c;其实就是购买这四个商品 but当我购买第一个商品时 回显 意思就是只能输入一个字…...

72.Linux系统下printf函数的输出问题

目录 printf函数输出问题 为啥要放到缓冲区呢&#xff1f; \n 强制刷新缓冲区 fflush 强制刷新缓冲区 printf函数输出问题 在 Linux 下&#xff0c;printf 函数通常会先将输出放入缓冲区而不是立即将其发送到终端或文件。这是为了提高性能&#xff0c;因为逐个字符或逐个…...

Ubuntu20.4搭建基于iRedMail的邮件服务器

iRedMail 是一个基于 Linux/BSD 系统的零成本、功能完备、成熟的邮件服务器解决方案。基于ubuntu20.4搭建基于iRedMail的邮件服务器包括环境配置&#xff0c;iRedMail安装与配置&#xff0c;iRedMail调整邮件附件大小等3个小节进行描述。具体如下详细描述。 1 环境配置 1.设置…...

大数据-Spark-Spark开发高频面试题

一、spark的内存分布 堆内内存&#xff1a;在这使用堆内内存的时候&#xff0c;如果我们设置了堆内内存2个g的话&#xff0c;读取的数据也是两个g&#xff0c;此时又来两个g的数据&#xff0c;这样就会产生OOM溢出&#xff0c;因为处理完两个g的数据&#xff0c;并不会马上进行…...

云原生容器平台——新华资产数字化转型加速器

新华资产管理股份有限公司&#xff08;以下简称“新华资产”&#xff09;于2006年5月经中国保险监督管理委员会批准、7月3日正式挂牌成立&#xff0c;是国内首批专业保险资产管理机构。2020年上半年&#xff0c;公司管理的资产规模突破万亿元人民币&#xff0c;投资收益水平居行…...

ubuntu 22.04运行opencv4的c++程序遇到的问题

摘要&#xff1a;本文介绍一下在ubuntu系统中&#xff0c;运行一个最简单的opencv4程序都出问题的解决方法&#xff0c;并对其基本原理作简单阐述。解决问题的方法有很多&#xff0c;本文只提供其中一种。 opencv版本是4.2.0&#xff0c;ubuntu版本是20.04 查询opencv版本的指…...

MDPI模板报错的问题---提示缺少sty文件

MDPI模板报错的问题—提示缺少sty文件 平时大多数提交IEEE trans模板时大多使用CTEX编译&#xff0c;然而&#xff0c;MDPI模板需要用texlive&#xff0c;二者之间如果先安装CTEX后安装texlive将会导致库文件的冲突。结果将会报缺少sty的文件错。网上提供了很多解决方案&#…...

【教程】微信小程序导入外部字体详细流程

前言 在微信小程序中&#xff0c;我们在wxss文件中通过font-family这一CSS属性来设置文本的字体&#xff0c;并且微信小程序有自身支持的内置字体&#xff0c;可以通过代码提示查看微信小程序支持字体&#xff1a; 这些字体具体是什么样式可以参考&#xff1a; 微信小程序--字…...

关于Kali部署OneForAll,不能运行问题

问题描述 运行OneForAll后&#xff0c;出现了如下报错 问题&#xff1a; importterror:无法从’re’导入名称’sre_parse’ (/usr/lib/python3.11/re/init.py) Traceback (most recent call last):File "/home/kali/桌面/App/OneForAll/oneforall.py", line 16, in…...

vue3中使用el-upload + tui-image-editor进行图片处理

效果如下 看之前请先看上一篇《vue3中使用组件tui-image-editor进行图片处理》中的 1、第一步安装 2、第二部封装组件 本篇只是在这基础上结合el-upload使用组件 3、第三步结合el-upload使用组件 <template><el-dialog:title"dialogTitle":modelValue&qu…...

二叉树顺序结构及实现

&#x1f449;二叉树顺序结构及实现 1.二叉树的顺序结构2.堆的概念及结构3.堆的实现3.1堆向下调整算法3.2堆向上调整算法 4.堆的创建4.1堆创建方法14.1.1构建堆结构体4.1.2堆的初始化4.1.3堆数据添加向上调整4.1.4主函数内容 4.2堆的创建方法24.2.1堆数据添加向下调整 4.3堆数据…...

python读取influxdb中数据

示例代码一&#xff1a;从infludb中获取指定时间段time和value值&#xff0c;并作图保存 from influxdb_client import InfluxDBClient import matplotlib.pyplot as plt# InfluxDB连接信息 url "http://localhost:8086" token "your_token" org "…...

【网络编程】UDP Socket编程

UDP Socket编程 一. DatagramSocket二. DatagramPacket三. InetSocketAddress四. 执行流程五. 代码示例: UDP 回显服务器 数据报套接字&#xff1a; 使用传输层 UDP 协议 UDP: 即 User Datagram Protocol&#xff08;用户数据报协议&#xff09;&#xff0c;传输层协议。 UDP…...

[GIT]版本控制工具

[GIT]版本控制工具 Git 的命令Git 的配置信息查看现有 Git 配置信息设置 Git 配置信息用户信息配置文本编辑器配置差异分析工具配置 编辑 Git 配置文件 Git 仓库操作初始化 Git 仓库克隆 Git 仓库Git 分支仓库创建Git 远程仓库命令 Git 提交历史Git 标签添加标签查看已有标签删…...

Linux文件管理命令

Linux命令行 命令空格参数(可写可不写)空格文件(可写可不写)ls/opt 根目录下的opt文件夹ls-a 显示所有文件及隐藏文件/optls -l 详细输出文件夹内容 ls -h 输出文件大小(MB...)ls--full-time 完整时间格式输出ls-d 显示文件夹本身信息&#xff0c;不输出内容ls-t 根据最后修改…...

Netty面试题(三)

文章目录 前言一、如何选择序列化协议&#xff1f;二、Netty 的零拷贝实现&#xff1f;总结 前言 如何选择序列化协议&#xff1f;Netty 的零拷贝实现&#xff1f; 一、如何选择序列化协议&#xff1f; 具体场景 对于公司间的系统调用&#xff0c;如果性能要求在 100ms 以上的…...

risc-v dv源代码分析

地址为 GitHub - chipsalliance/riscv-dv: Random instruction generator for RISC-V processor verificationRandom instruction generator for RISC-V processor verification - GitHub - chipsalliance/riscv-dv: Random instruction generator for RISC-V processor verif…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

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

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

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

一些实用的chrome扩展0x01

简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序&#xff0c;无论是测试应用程序、搜寻漏洞还是收集情报&#xff0c;它们都能提升工作流程。 FoxyProxy 代理管理工具&#xff0c;此扩展简化了使用代理&#xff08;如 Burp…...