【C++】————智能指针
作者主页: 作者主页
本篇博客专栏:C++
创作时间 :2024年8月20日
一,什么是智能指针
在C++中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露。解决这个问题最有效的方法是使用智能指针(smart pointer)。智能指针是存储指向动态分配(堆)对象指针的类,用于生存期的控制,能够确保在离开指针所在作用域时,自动地销毁动态分配的对象,防止内存泄露。智能指针的核心实现技术是引用计数,每使用它一次,内部引用计数加1,每析构一次内部的引用计数减1,减为0时,删除所指向的堆内存。
- c++中用的最多的是下面三种智能指针
C++11中提供了三种智能指针,使用这些智能指针时需要引用头文件<memory>
- std::shared_ptr:共享的智能指针
- std::unique_ptr:独占的智能指针
- std::weak_ptr:弱引用的智能指针,它不共享指针,不能操作资源,是用来监视shared_ptr的。
二,共享的智能指针shared_ptr
- 首先了解一下基本概念,再看代码,会学的很快
1. shared_ptr的初始化
共享智能指针是指多个智能指针可以同时管理同一块有效的内存,共享智能指针shared_ptr 是一个模板类,如果要进行初始化有三种方式:通过构造函数、std::make_shared辅助函数以及reset方法。共享智能指针对象初始化完毕之后就指向了要管理的那块堆内存,如果想要查看当前有多少个智能指针同时管理着这块内存可以使用共享智能指针提供的一个成员函数use_count
2.获取原始指针
对应基础数据类型来说,通过操作智能指针和操作智能指针管理的内存效果是一样的,可以直接完成数据的读写。但是如果共享智能指针管理的是一个对象,那么就需要取出原始内存的地址再操作,可以调用共享智能指针类提供的get()方法得到原始地址
3. 指定删除器
当智能指针管理的内存对应的引用计数变为0的时候,这块内存就会被智能指针析构掉了。另外,我们在初始化智能指针的时候也可以自己指定删除动作,这个删除操作对应的函数被称之为删除器,这个删除器函数本质是一个回调函数,我们只需要进行实现,其调用是由智能指针完成的。
下面我们来看一下代码如何实现:
#pragma once
#include <iostream>
#include <functional>namespace zy
{template<class T>class shared_ptr{public:shared_ptr(T* ptr = nullptr) : _ptr(ptr), _pcount(ptr ? new int(1) : nullptr){std::cout << "shared_ptr(T* ptr)" << std::endl;}template<class D>shared_ptr(T* ptr = nullptr,D del): _ptr(ptr), _pcount(ptr ? new int(1) : nullptr), _del(del){}shared_ptr(const shared_ptr& sp) : _ptr(sp._ptr), _pcount(sp._pcount){++(*_pcount);std::cout << "Copy constructor" << std::endl;}shared_ptr& operator=(const shared_ptr& sp){if (this != &sp){// 释放当前对象管理的资源(如果有)this->Realease();_ptr = sp._ptr;_pcount = sp._pcount;++(*_pcount);}return *this;}~shared_ptr(){Realease();}void Realease(){if (_pcount && --(*_pcount) == 0){//delete _ptr;_del(_ptr);delete _pcount;_ptr = nullptr;_pcount = nullptr;}}T* get(){return _ptr;}int use_count(){return _pcount ? *_pcount : 0;}T& operator*() { return *_ptr; }T* operator->() { return _ptr; }private:T* _ptr;int* _pcount;fuction<void(T* ptr)>_del = [](T* ptr) {delete ptr};};
}
三,独占的智能指针unique_ptr
1. 初始化
std::unique_ptr是一个独占型的智能指针,它不允许其他的智能指针共享其内部的指针,可以通过它的构造函数初始化一个独占智能指针对象,但是不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr。
2. 删除器
unique_ptr指定删除器和shared_ptr指定删除器是有区别的,unique_ptr指定删除器的时候需要确定删除器的类型,所以不能像shared_ptr那样直接指定删除器
#pragma once
#include <iostream>template <typename T>
class unique_ptr {
public:// 构造函数,接受一个原始指针并接管其所有权unique_ptr(T* ptr = nullptr) : ptr_(ptr) {}// 移动构造函数,转移所有权unique_ptr(unique_ptr&& other) noexcept : ptr_(other.ptr_) {other.ptr_ = nullptr;}// 移动赋值运算符,转移所有权unique_ptr& operator=(unique_ptr&& other) noexcept {if (this!= &other) {reset();ptr_ = other.ptr_;other.ptr_ = nullptr;}return *this;}// 析构函数,释放所管理的资源~unique_ptr() {reset();}// 解引用操作符T& operator*() const {return *ptr_;}// 箭头操作符T* operator->() const {return ptr_;}// 获取原始指针T* get() const {return ptr_;}// 释放所管理的资源并将指针置为 nullptrvoid reset(T* ptr = nullptr) {if (ptr_) {delete ptr_;}ptr_ = ptr;}private:T* ptr_;
};
四, 弱引用的智能指针weak_ptr
弱引用智能指针std::weak_ptr可以看做是shared_ptr的助手,它不管理shared_ptr内部的指针。std::weak_ptr没有重载操作符*和->,因为它不共享指针,不能操作资源,所以它的构造不会增加引用计数,析构也不会减少引用计数,它的主要作用就是作为一个旁观者监视shared_ptr中管理的资源是否存在。
1 初始化
弱引用智能指针std::weak_ptr可以看做是shared_ptr的助手,它不管理shared_ptr内部的指针。std::weak_ptr没有重载操作符*和->,因为它不共享指针,不能操作资源,所以它的构造不会增加引用计数,析构也不会减少引用计数,它的主要作用就是作为一个旁观者监视shared_ptr中管理的资源是否存在。
#include <iostream>
#include <memory>
using namespace std;int main()
{shared_ptr<int> sp(new int);weak_ptr<int> wp1;weak_ptr<int> wp2(wp1);weak_ptr<int> wp3(sp);weak_ptr<int> wp4;wp4 = sp;weak_ptr<int> wp5;wp5 = wp3;return 0;
}
- weak_ptr<int> wp1;构造了一个空weak_ptr对象
- weak_ptr<int> wp2(wp1);通过一个空weak_ptr对象构造了另一个空weak_ptr对象
- weak_ptr<int> wp3(sp);通过一个shared_ptr对象构造了一个可用的weak_ptr实例对象
- wp4 = sp;通过一个shared_ptr对象构造了一个可用的weak_ptr实例对象(这是一个隐式类型转换)
- wp5 = wp3;通过一个weak_ptr对象构造了一个可用的weak_ptr实例对象
- 通过调用
std::weak_ptr
类提供的use_count()
方法可以获得当前所观测资源的引用计数
2.常用函数
通过调用std::weak_ptr类提供的expired()方法来判断观测的资源是否已经被释放
通过调用std::weak_ptr类提供的lock()方法来获取管理所监测资源的shared_ptr对象
通过调用std::weak_ptr类提供的reset()方法来清空对象,使其不监测任何资源
- 利用
weak_ptr可以解决shared_ptr的一些问题
- 返回管理this的shared_ptr
- 解决循环引用问题
最后:
十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:
1.一个冷知识:
屏蔽力是一个人最顶级的能力,任何消耗你的人和事,多看一眼都是你的不对。
2.你不用变得很外向,内向挺好的,但需要你发言的时候,一定要勇敢。
正所谓:君子可内敛不可懦弱,面不公可起而论之。
3.成年人的世界,只筛选,不教育。
4.自律不是6点起床,7点准时学习,而是不管别人怎么说怎么看,你也会坚持去做,绝不打乱自己的节奏,是一种自我的恒心。
5.你开始炫耀自己,往往都是灾难的开始,就像老子在《道德经》里写到:光而不耀,静水流深。
最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)
愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!
相关文章:

【C++】————智能指针
作者主页: 作者主页 本篇博客专栏:C 创作时间 :2024年8月20日 一,什么是智能指针 在C中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露。解决这个问题最有效的方法是使用智能指针&…...
GT IP中CC序列(Clock Correction Sequence)的周期性
CC序列(Clock Correction Sequence),即时钟校正序列,在数字通信中扮演着至关重要的角色。这一序列的周期性插入机制,旨在确保发送器和接收器之间的时钟同步,从而维持数据传输的准确性和稳定性。以下是CC序列…...
grafana pod 无法启动 Only one datasource per organization can be marked as default
标题信息 helm 部署的 prometheus 全栈监控 chart 为 prometheus-community/kube-prometheus-stack helm 部署的 loki 日志系统 chart 为 grafana/loki-stack 问题描述 grafana pod 启动不了,查看该pod 日志报错如下 logger=provisioning t=2024-08-21T06:42:45.954318228…...

你是如何克服编程学习中的挫折感的?(-@-^-0-)
在编程学习中遇到挫折感是极为常见且正常的现象,因为编程往往涉及解决复杂问题、理解抽象概念以及不断试错的过程。 以下是一些建议,帮助你在面对挫折时调整心态,继续前行: 接受失败是成长的一部分:首先要认识到&#…...
大数据技术之Zookeeper(1)
目录 Zookeeper 入门 概述 Zookeeper的主要特点包括: Zookeeper的应用场景: Zookeeper的基本概念: 架构: Zookeeper工作机制 Zookeeper数据结构 Znode(Zookeeper Node) Znode的类型 Znode路径 Znode属性 Wa…...
鸿蒙学习(四):泛型空安全模块导入导出
泛型与函数 泛型类型和函数允许创建的代码在各种类型上运行,而不仅支持单一类型。 泛型类和接口(Element) 类和接口可以定义为泛型,将参数添加到类型定义中,如以下示例中的类型参数Element: class CustomStack<Element>…...
无人机(Unmanned Aerial Vehicle, UAV)视觉感知论文汇总
综述类 A Survey of Object Detection for UAVs Based on Deep LearningDeep Learning for UAV-based Object Detection and Tracking:A surveyMoving Target Tracking by Unmanned Aerial Vehicle:A Survey and TaxonomyVision-Based Learning for Dro…...
【ORACLE】 ORA-01691: Lob 段无法通过 8192 (在表空间 XXX_SPACE 中) 扩展
ORA-01691错误通常表示Oracle数据库在尝试扩展LOB段时无法为表空间分配更多的空间。这个问题通常由表空间容量不足引起。根据搜索结果,以下是几种可能的解决方案: 检查并扩大表空间:首先,确认表空间是否已经达到其最大容量。可以使…...
Java之静态代理与动态代理的区别
🍁 作者:知识浅谈,CSDN签约讲师,CSDN博客专家,华为云云享专家,阿里云专家博主 📌 擅长领域:全栈工程师、爬虫、ACM算法 🔥 微信:zsqtcyw 联系我领取学习资料 …...

公司内网监控软件有哪些?(2024年10款最新款推荐内网监控软件)
在2024年,公司内网监控软件市场提供了多种选择,以满足不同企业的监控需求。 以下是一些值得推荐的最新款内网监控软件: 1. Performance Monitor 核心功能:不仅是一款局域网监控软件,更是一个全面的内网安全管理解决方…...
CUDA编程07 - 卷积的优化
一:概述 在接下来的几篇文章中,我们将讨论一组重要的并行计算模式。这些模式是许多并行算法的基础,这些算法出现在许多并行应用中。我们将从卷积开始,卷积是一种流行的数组操作,广泛应用于信号处理、数字录音、图像处理、视频处理和计算机视觉等领域。在这些应用领域中,卷…...

解锁高效办公新姿势:SSO单点登录+企业网盘完美搭配
在现代互联网环境中,随着企业业务的不断扩展,多系统、多应用的集成成为常态。为了提升用户体验,减少用户在不同系统间切换的繁琐,单点登录(SSO, Single Sign-On)技术应运而生。 本文将详细介绍SSO单点登录的…...

[数据集][目标检测]竹子甘蔗发芽缺陷检测数据集VOC+YOLO格式2953张3类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2953 标注数量(xml文件个数):2953 标注数量(txt文件个数):2953 标注…...

RTC碰到LXTAL低频晶振停振怎么办?
GD32F303的RTC模块框图如下图所示,RTC时钟源可选择HXTAL/128、LXTAL或IRC40K,一般为了实现更精准的RTC时间,MCU系统均会外挂32.768KHz LXTAL低频晶振,但由于低频晶振负阻抗较大,不容易起振,若外部电路布线、…...

矩阵中的最大得分(Lc3148)——动态规划
给你一个由 正整数 组成、大小为 m x n 的矩阵 grid。你可以从矩阵中的任一单元格移动到另一个位于正下方或正右侧的任意单元格(不必相邻)。从值为 c1 的单元格移动到值为 c2 的单元格的得分为 c2 - c1 。 你可以从 任一 单元格开始,并且必须…...

C++ 设计模式(4. 建造者模式)
建造者模式(也被成为生成器模式),是一种创建型设计模式,软件开发过程中有的时候需要创建很复杂的对象,而建造者模式的主要思想是将对象的构建过程分为多个步骤,并为每个步骤定义一个抽象的接口。具体的构建…...
Arbitrum 和 Optimism Layer 2 扩展方案对比
Arbitrum 和 Optimism 对比分析 Arbitrum 和 Optimism 是两个以太坊 Layer 2 扩展方案,它们都使用了 Optimistic Rollup 技术来提升以太坊的可扩展性并降低交易成本。虽然它们有着相似的目标,但在架构设计、性能表现和费用结构上各有特点。 一、架构与…...

热门的蓝牙耳机中,哪种类型更受欢迎?四款热度高的开放式耳机
在如今的耳机市场中,开放式耳机异军突起,成为了众多消费者的新宠。如果你还在为传统入耳式耳机带来的不适而烦恼,那么开放式耳机绝对值得你一试。它不仅能让你在享受音乐的同时,依然可以清晰感知周围环境,保障你的安全…...
基于web的亚热带常见自然林病虫害识别系统——总结与展望
文章目录 一、前言二、总结三、展望参考文献致谢一、前言 这个系列也迎来了结尾,最后说一些碎碎念… 二、总结 本文首先简要介绍了卷积神经网络的基本原理,以及在亚热带常见自然林植物识别领域的研究应用现状。 其重点研究了卷积神经网络在亚热带常见自然林植物叶片病害识…...
其他自动重试的注解
除了 Retryable 注解之外,Spring 提供了其他注解用于自动重试方法,主要包括以下几个注解: 1. Recover Recover 注解用于定义重试次数耗尽后执行的恢复方法。当 Retryable 注解的重试次数达到上限时,Recover 方法会被调用。这通常…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...