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

c++ 智能指针实战分析

一.智能指针的设计思路

  1. 智能指针是类模板,再栈上创建智能指针对象。
  2. 把普通指针交给智能指针对象。
  3. 智能指针对象过期时,调用析构函数释放普通指针的内存。
  • 智能指针的类型
  1. auto_ptr是C++98的标准,c++17已经弃用。
  2. unique_ptr、shared_ptr和weak_ptr是C++11标准的。

二.智能指针 unique_ptr

C++智能指针unique_ptr是C++11标准库中提供的一种智能指针类型,用于管理动态分配的资源,主要用来避免内存泄漏和简化资源管理。unique_ptr是独占所有权的智能指针,即同一时间只能有一个unique_ptr指向特定的资源,当unique_ptr被销毁时,它所管理的资源会被自动释放。

1.基本用法

  1. 方法1:
unique_ptr<AA>p0(new AA("小明"));//分配内存并初始化
  1. 方法2:
unique_ptr<AA>p0=make_unique<AA>("小明");//c++14标准
  1. 方法3:
AA*p=new AA("小明");
unique_ptr<AA>p0(p);//用已存在的地址初始化
  1. 方法4:get()方法可以返回裸指针

2. 基本定义

  • 包含头文件
#include <memory>

以下是unique_ptr的简化版本的类模板定义(省略了部分实现细节):

template <typename T>
class unique_ptr {
private:T* ptr;public:// 构造函数unique_ptr(T* p) : ptr(p) {}// 移动构造函数unique_ptr(unique_ptr&& other) noexcept : ptr(other.ptr) {other.ptr = nullptr;}// 析构函数~unique_ptr() {delete ptr;}// 禁止拷贝和赋值unique_ptr(const unique_ptr&) = delete;unique_ptr& operator=(const unique_ptr&) = delete;// 移动赋值运算符unique_ptr& operator=(unique_ptr&& other) noexcept {if (this != &other) {delete ptr;ptr = other.ptr;other.ptr = nullptr;}return *this;}// 获取裸指针T* get() const {return ptr;}// 重载运算符->T* operator->() const {return ptr;}// 重载解引用运算符*T& operator*() const {return *ptr;}// 释放资源void reset() {delete ptr;ptr = nullptr;}
};

3.实战测试

#include<iostream>
using namespace std;#include<vector>
#include<memory>//智能指针头文件class AA
{
public:string m_name;AA():m_name("未定义") { cout << m_name << "调用构造函数AA()" << endl; }AA(const string& name) :m_name(name) { cout << "调用构造函数(" << m_name << ")" << endl; }~AA() { cout << "调用了析构函数~AA(" << m_name << ")" << endl; }};int main()
{AA* p1 = new AA("小明");//使用智能指针来管理p//这里AA的意思是要管理的普通指针类型是AA//智能指针本来就是用来管理指针的所以不需要使用AA*unique_ptr<AA>ptr1(p1);//与正常指针用法一致cout << "m_name " << (*ptr1).m_name << endl;cout << "m_name " << ptr1->m_name << endl;cout << "m_name " << (*p1).m_name << endl;cout << "m_name " << p1->m_name << endl;//system("pause");不能使用这个,否则程序无法正常关闭,析构函数无法成功调用return 0;
}
  • 执行结果

在这里插入图片描述

三.智能指针 shared_ptr

在 C++ 中,智能指针是一种用于管理动态分配对象的指针类,可以帮助开发人员更好地管理内存资源,避免内存泄漏等问题。std::shared_ptr 是 C++11 标准库中提供的一种智能指针,用于共享所有权的指针管理。std::shared_ptr 可以自动追踪有多少个指针共享同一个对象,并在对象不再被引用时安全地释放内存。共享指针的引用计数会在创建、复制和销毁时进行递增和递减,当引用计数为 0 时,内存资源就会被释放。

使用方法:(和unique_ptr基本一样的)

#include <memory>
std::shared_ptr<int> sharedPtr = std::make_shared<int>(10);
智能指针的复制:
std::shared_ptr<int> sharedPtr2 = sharedPtr;
使用 std::make_shared 创建对象时,可以减少内存分配和额外的虚拟函数调用。可以使用 .use_count() 方法获取当前共享指针的引用计数。std::shared_ptr 还支持自定义的删除器,用于指定释放内存时的操作。

总的来说,std::shared_ptr 可以帮助避免潜在的内存泄漏和悬空指针问题,提高代码的健壮性和可维护性。

  • 实战测试
#include<iostream>
using namespace std;#include<vector>
#include<memory>//智能指针头文件class AA
{
public:string m_name;AA() :m_name("未定义") { cout << m_name << "调用构造函数AA()" << endl; }AA(const string& name) :m_name(name) { cout << "调用构造函数(" << m_name << ")" << endl; }~AA() { cout << "调用了析构函数~AA(" << m_name << ")" << endl; }};int main()
{AA* p1 = new AA("小明");//使用智能指针来管理p//这里AA的意思是要管理的普通指针类型是AA//智能指针本来就是用来管理指针的所以不需要使用AA*shared_ptr<AA>ptr1(p1);//与正常指针用法一致cout << "m_name " << (*ptr1).m_name << endl;cout << "m_name " << ptr1->m_name << endl;cout << "m_name " << (*p1).m_name << endl;cout << "m_name " << p1->m_name << endl;cout << "use_count=" << ptr1.use_count() << endl;//system("pause");不能使用这个,否则程序无法正常关闭,析构函数无法成功调用return 0;
}
  • 输出结果
    在这里插入图片描述

四.智能指针 weak_ptr

在 C++ 中,std::weak_ptr 是另一种智能指针,用于解决 std::shared_ptr 循环引用所带来的问题。std::weak_ptr 允许你观察指向的对象,但不拥有其所有权。通常与 std::shared_ptr 一起使用,可以避免循环引用导致的内存泄漏问题。

以下是一些关于 std::weak_ptr 的重要点和用法:

  1. 通过 std::weak_ptr 对象获std::shared_ptr 对象:
std::shared_ptr<int> sharedPtr = std::make_shared<int>(10);
std::weak_ptr<int> weakPtr = sharedPtr;
  1. 使用 std::lock_guard 和 std::shared_ptr::lock 方法来安全地获取 std::shared_ptr 对象,避免访问已经释放的对象:
if (std::shared_ptr<int> sharedPtr = weakPtr.lock()) {// 使用 sharedPtr 访问对象
} else {// 对象已被释放
}
  1. std::weak_ptr 不增加引用计数,只是提供了对对象的观察能力,也不会阻止对象的释放。

  2. 可以使用 std::weak_ptr 来打破循环引用,让对象能够被正确地释放。

std::weak_ptr 是一种很有用的工具,可以帮助解决在使用智能指针时可能会遇到的循环引用问题,确保内存资源能够正确地释放,提高程序的稳定性和可靠性。

  • 实战测试
#include<iostream>
using namespace std;#include<vector>
#include<memory>//智能指针头文件class BB;class AA
{
public:string m_name;AA() :m_name("未定义") { cout << m_name << "调用构造函数AA()" << endl; }AA(const string& name) :m_name(name) { cout << "调用构造函数(" << m_name << ")" << endl; }~AA() { cout << "调用了析构函数~AA(" << m_name << ")" << endl; }shared_ptr<BB>p_B;};class BB
{
public:string m_name;BB() :m_name("未定义") { cout << m_name << "调用构造函数BB()" << endl; }BB(const string& name) :m_name(name) { cout << "调用构造函数(" << m_name << ")" << endl; }~BB() { cout << "调用了析构函数~BB(" << m_name << ")" << endl; }shared_ptr<AA>p_A;
};int main()
{AA* p1 = new AA("小明");BB* p2 = new BB("李华");//使用智能指针来管理p//这里AA的意思是要管理的普通指针类型是AA//智能指针本来就是用来管理指针的所以不需要使用AA*shared_ptr<AA>ptr1(p1);shared_ptr<BB>ptr2 (p2);//与正常指针用法一致cout << "ptr1->m_name " << (*ptr1).m_name << endl;cout << "ptr1->m_name " << ptr1->m_name << endl;cout << "ptr1->m_name " << (*p1).m_name << endl;cout << "ptr1->m_name " << p1->m_name << endl;cout << "ptr1->use_count=" << ptr1.use_count() << endl;cout << "ptr2->m_name " << (*ptr2).m_name << endl;cout << "ptr2->m_name " << ptr2->m_name << endl;cout << "ptr2->m_name " << (*p2).m_name << endl;cout << "ptr2->m_name " << p2->m_name << endl;cout << "ptr2->use_count=" << ptr2.use_count() << endl;ptr1->p_B = ptr2;ptr2->p_A = ptr1;//system("pause");不能使用这个,否则程序无法正常关闭,析构函数无法成功调用return 0;
}
  • 由于相互执行都在等待对方释放资源,结果两方都无法释放资源
    在这里插入图片描述

  • 解决方法:使用weak_ptr

相关文章:

c++ 智能指针实战分析

一.智能指针的设计思路 智能指针是类模板&#xff0c;再栈上创建智能指针对象。把普通指针交给智能指针对象。智能指针对象过期时&#xff0c;调用析构函数释放普通指针的内存。 智能指针的类型 auto_ptr是C98的标准&#xff0c;c17已经弃用。unique_ptr、shared_ptr和weak_…...

3D Web轻量引擎HOOPS Web Platform赋能AEC行业数字化,高效渲染与多格式支持!

在建筑、工程和施工&#xff08;AEC&#xff09;行业&#xff0c;数字化转型和高效协作正变得越来越重要。为应对日益复杂的项目需求和不断提升的质量标准&#xff0c;AEC企业需要一种强大的工具来实现高效的3D可视化和数据管理。HOOPS Web Platform作为一款综合性3D开发平台&a…...

学术英语写作为什么会成为留学生的压力?

对留学党来说&#xff0c;从出国前的标准化测试、申请文书&#xff0c;到留学后的学业要求&#xff0c;都需要用到学术英语写作。可以说&#xff0c;学术英语写作对留学生涯有着重要影响。 然而&#xff0c;这却是令很多中国学生头疼的问题&#xff0c;中国学生往往在数学、物…...

docker 安装达梦8

背景 X86-64架构使用Docker安装dm8_20240422_x86_rh6_64_rq_std_8.1.3.100_pack2.tar 1.下载Docker安装包 达梦官网下载dm8_20240422_x86_rh6_64_rq_std_8.1.3.100_pack2.tar安装包 快速下载通道&#xff1a; 达梦镜像包 2.将安装包上传至服务器&#xff0c;并加载镜像 拷…...

npm常用命令大全(非常详细)

npm&#xff08;Node Package Manager&#xff09;是Node.js的包管理工具&#xff0c;它允许你安装、更新、删除和管理Node.js项目的依赖。 以下是npm的一些常用命令&#xff0c;按照不同的功能进行分类和解释&#xff1a; 1. 初始化项目 init # 初始化一个新的npm项目&…...

东西方文化与管理探讨汉捷咨询汉捷咨询

东西方文化的发展不同&#xff0c;对于管理实践的影响也不相同。汉捷咨询从东西方文化的差异以管理体系的差异进行深层次分析&#xff0c;希望这些分析对企业家的管理实践起到良好的启发作用。 东西方文化的差异 东西方人在思维方式上存在的差异&#xff0c;其根源是什么呢&a…...

行业案例 | 智能终端设备的数据基础从哪儿来?

智能终端的快速发展让我们在许多科幻电影中看到的“未来场景”正在一步步变为现实&#xff1a;智能家居正在解放我们的双手&#xff0c;工业机器人让生产效率倍增&#xff0c;智能穿戴设备让我们便利地感知自身与外部的连结……然而&#xff0c;要想让万物“智联”&#xff0c;…...

《Windows API每日一练》6.1 鼠标基础知识

本节我们讲述鼠标的一些基础知识。 本节必须掌握的知识点&#xff1a; 鼠标 6.1.1 鼠标 鼠标是1964年由Douglas Engelbart发明的&#xff0c;用来取代由键盘输入的繁琐指令&#xff0c;简化电脑操作。早期的鼠标是单键鼠标&#xff0c;只有一个键&#xff0c;后来逐步改进为双…...

闹大了!OpenAI 宣布终止提供API服务

事件背景&#xff1a; OpenAI宣布终止对中国提供API服务&#xff0c;影响中国大陆的API开发者。受影响的开发者收到OpenAI的警告信&#xff0c;要求7月9日后停止服务。 OpenAI的业务和营收&#xff1a; 2023年营收16亿美元&#xff0c;2024年上半年年化营收达34亿美元。营收来…...

java里的空接口实现它有什么用?

我们在看源码时&#xff0c;经常会看到一些空接口&#xff0c;这些空接口里没有一个方法&#xff0c;实现它有什么作用呢&#xff1f;让我们先找几个常见的空接口看看。 一、Serializable接口 在Java中&#xff0c;一个常见的空接口就是java.io.Serializable。 public inter…...

Spring的jar包下载(最新版6.0版本)

1.在Spring官网的projects下面点击spring-framework 2.进入github官网 3.进入github后往下滑&#xff0c;点击Spring Framework Artifacts 4.往下滑找到 点击 5.在左边先点击Artifacts&#xff0c;在右边找到 libs-snapshot&#xff0c;展开libs-snapshot&#xff08;之前其他…...

解决Java中数据库连接泄露的技术

解决Java中数据库连接泄露的技术 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 介绍 在Java应用程序中&#xff0c;数据库连接的泄露是一个常见且影响性能的…...

网页视频录制,分享3种好方法

随着互联网的飞速发展&#xff0c;视频内容在网页上的呈现与传播变得日益普遍。网页视频录制作为一种重要的技术手段&#xff0c;不仅方便了我们获取和保存网页上的视频内容&#xff0c;还为教育、娱乐、营销等多个领域提供了全新的应用可能。 但是网页视频怎么录制&#xff1…...

LeNet网络的实现

LeNet网络的实现 import torch from torch import nn from d2l import torch as d2lx 28 net nn.Sequential(nn.Conv2d(1, 6, kernel_size5, padding2), nn.Sigmoid(),nn.AvgPool2d(kernel_size2, stride2),nn.Conv2d(6, 16, kernel_size5), nn.Sigmoid(),nn.AvgPool2d(kerne…...

华为HCIP Datacom H12-821 卷6

1.单选题 下面是一台路由器的部分配置,关于该部分配置描述正确的是,[HUAWEllJip ip-prefix plpermit 10.0.192.0 8 greater-equal 17 less-equal 18 A、10.0.192.0/8 网段内,掩码长度为 20 的路由会匹配到该前缀列表,匹配规则为允许 B、10.0.192.0/8 网段内,掩码长度为…...

深入理解SQL优化:理论与实践的结合

深入理解SQL优化&#xff1a;理论与实践的结合 SQL优化是数据库性能优化的核心&#xff0c;通过优化SQL查询&#xff0c;可以极大地提高数据库的响应速度和资源利用效率。本文将以SQL优化的理论基础和实践应用为主线&#xff0c;结合具体案例&#xff0c;系统化地介绍如何有效…...

PostgreSQL 高级功能与扩展(九)

1. JSONB 数据类型与操作 1.1 JSONB 简介 JSONB 是 PostgreSQL 中的一种数据类型&#xff0c;用于存储 JSON 格式的数据&#xff0c;并提供高效的查询和索引功能。 1.1.1 创建 JSONB 列 CREATE TABLE json_data ( id SERIAL PRIMARY KEY, data JSONB ); 1.2 JSONB 查询与索…...

【LinuxC语言】UDP数据收发

文章目录 前言udp流程图udp函数介绍bind函数recvfrom函数sendto函数示例代码总结前言 在计算机网络中,UDP(用户数据报协议)是一种无连接的传输层协议,它允许应用程序快速地发送短的消息或数据报。由于UDP不需要建立和断开连接,因此它的传输速度往往比其他协议更快,但它也…...

【深度学习驱动流体力学】计算流体力学openfoam-paraview与python3交互

目的1:配置 ParaView 中的 Python Shell 和 Python 交互环境 ParaView 提供了强大的 Python 接口,允许用户通过 Python 脚本来控制和操作其可视化功能。在 ParaView 中,可以通过 View > Python Shell 菜单打开 Python Shell 窗口,用于执行 Python 代码。要确保正确配置 …...

EWM学习之旅-1-EWM100

系统学习一个业务模块已经变得越来越重要&#xff0c;开始吧&#xff0c;EWM&#xff01; EWM的Learning Journey中包括7本 ebook,100/110/115/120/125/130/140&#xff0c;一本一本的啃吧&#xff0c;相信很多内容是重复的。 EWM100很适合初学者&#xff0c;了解概念术语&…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...