C++中的智能指针

指针用于访问程序外部的资源——如堆内存。因此,访问堆内存(如果在堆中创建了任何内容)时,需要使用指针。当访问任何外部资源时,我们只使用该资源的副本。如果我们对其进行修改,我们只会改变副本的版本。但如果我们使用指针来访问资源,我们将能够修改原始资源。

C++ 中普通指针的一些问题如下:

- 内存泄漏:当程序反复分配内存但从未释放时,会导致内存泄漏。这会导致过度的内存消耗,最终可能导致系统崩溃。
- 悬空指针:悬空指针是指在对象从内存中被释放后,没有修改指针的值。此时,指针仍然指向已释放的内存。
- 野指针:野指针是已经声明并分配了内存的指针,但该指针从未初始化为指向有效的对象或地址。
- 数据不一致:数据不一致发生在一些数据存储在内存中,但没有以一致的方式更新。

// C++ 程序演示指针的工作方式
#include <iostream>
using namespace std;class Rectangle {
private:int length;int breadth;
};void fun() {// 使用指针 p 并动态创建一个 Rectangle 对象Rectangle* p = new Rectangle();
}int main() {// 无限循环while (1) {fun();}
}

输出

Memory limit exceeded

解释:

fun 函数中,创建了一个指针 p,它指向一个 Rectangle 对象。这个对象包含两个整数:lengthbreadth。当 fun 函数结束时,指针 p 会被销毁,因为它是一个局部变量。然而,它占用的内存并没有被释放,因为我们忘记使用 delete p; 来删除它。这意味着内存不会被释放,无法供其他资源使用。虽然我们不再需要这个变量,但我们需要释放内存。

main 函数中,fun 函数被无限次调用。每次调用都会创建 p,但内存没有被释放。随着调用的进行,内存不断增加,但不会被回收。由于没有释放的内存,最终会导致内存泄漏,整个堆内存可能因此变得无用。

智能指针

正如我们不自觉地发现的那样,未释放指针会导致内存泄漏,可能会导致程序崩溃。Java、C# 等语言通过垃圾回收机制来智能地释放未使用的内存。C++ 也有自己的机制:智能指针。当对象被销毁时,智能指针会自动释放内存。因此,我们不需要手动调用 delete 来释放内存。

智能指针是一个指针的封装类,重载了像 *-> 等操作符。智能指针类的对象看起来像普通指针,但与普通指针不同,它可以释放销毁的对象内存。

智能指针的思想是创建一个包含指针、析构函数和重载操作符(如 *->)的类。由于析构函数会在对象超出作用域时自动调用,因此动态分配的内存会自动被删除(或者引用计数会减少)。

// C++ 程序演示智能指针的工作方式
#include <iostream>
using namespace std;class SmartPtr {int* ptr; // 实际指针
public:// 构造函数explicit SmartPtr(int* p = NULL) { ptr = p; }// 析构函数~SmartPtr() { delete (ptr); }// 重载解引用操作符int& operator*() { return *ptr; }
};int main() {SmartPtr ptr(new int());*ptr = 20;cout << *ptr;// 我们不需要调用 delete ptr:当对象 ptr 超出作用域时// 它的析构函数会自动被调用,析构函数会删除 ptr。return 0;
}

输出

20

指针与智能指针的区别

指针智能指针
指针是一个存储内存地址和该内存位置数据类型信息的变量。指针是指向内存中某个位置的变量。智能指针是一个指针封装的栈分配对象。简单来说,智能指针是封装指针的类。
它不会在作用域结束时销毁。它在作用域结束时会销毁自己。
指针没有额外的特性,效率较低。智能指针效率更高,因为它具有内存管理的附加功能。
指针是手动管理的。智能指针是自动管理的。

注意:

这仅适用于 int 类型。那我们必须为每个对象创建智能指针吗?不,解决方案是模板。如下所示,T 可以是任何类型。

示例:使用模板解决问题

// C++ 程序演示模板的工作方式,并解决指针问题
#include <iostream>
using namespace std;// 通用智能指针类
template <class T> class SmartPtr {T* ptr; // 实际指针
public:// 构造函数explicit SmartPtr(T* p = NULL) { ptr = p; }// 析构函数~SmartPtr() { delete (ptr); }// 重载解引用操作符T& operator*() { return *ptr; }// 重载箭头操作符,这样可以像指针一样访问 T 的成员T* operator->() { return ptr; }
};int main() {SmartPtr<int> ptr(new int());*ptr = 20;cout << *ptr;return 0;
}

输出

20

注意:

智能指针也非常适用于资源管理,比如文件句柄或网络套接字等。

智能指针的类型

C++ 库提供了以下类型的智能指针实现:

  • auto_ptr

  • unique_ptr

  • shared_ptr

  • weak_ptr

auto_ptr

使用 auto_ptr,可以管理通过 new 表达式获取的对象,并在 auto_ptr 自身销毁时删除它们。当通过 auto_ptr 描述一个对象时,它会存储指向单个分配对象的指针。

注意:从 C++11 起,auto_ptr 被弃用。unique_ptr 是一个类似的功能,但它提供了更高的安全性。

unique_ptr

unique_ptr 只存储一个指针。我们可以通过移除当前对象并指向另一个对象来重新赋值。

实例

// C++ 程序演示 unique_ptr 的工作方式
// 这里我们展示 unique_ptr 指向 P1。
// 但是我们移除了 P1 并将其指向 P2,因此指针现在
// 指向 P2。#include <iostream>
using namespace std;
// 动态内存管理库
#include <memory>class Rectangle {int length;int breadth;public:Rectangle(int l, int b){length = l;breadth = b;}int area() { return length * breadth; }
};int main()
{// 智能指针unique_ptr<Rectangle> P1(new Rectangle(10, 5));cout << P1->area() << endl; // 打印 50// unique_ptr<Rectangle> P2(P1);unique_ptr<Rectangle> P2;P2 = move(P1);cout << P2->area() << endl;return 0;
}
50
50

shared_ptr

通过 shared_ptr,多个指针可以同时指向同一个对象,它将使用 use_count() 方法来维护引用计数。

// C++ 程序演示 shared_ptr 的工作方式
// 这里智能指针 P1 和 P2 都指向同一个
// 对象,并且它们都会保持该对象的引用。#include <iostream>
using namespace std;
// 动态内存管理库
#include <memory>class Rectangle {int length;int breadth;public:Rectangle(int l, int b){length = l;breadth = b;}int area() { return length * breadth; }
};int main()
{// 智能指针shared_ptr<Rectangle> P1(new Rectangle(10, 5));cout << P1->area() << endl;shared_ptr<Rectangle> P2;P2 = P1;cout << P2->area() << endl;cout << P1->area() << endl;cout << P1.use_count() << endl;return 0;
}
50
50
50
2

weak_ptr

weak_ptr 是一种智能指针,它持有一个非拥有的引用。它与 shared_ptr 非常相似,但不会维护引用计数。这样,指针不会对对象保持强引用,避免了通过 shared_ptr 创建的循环依赖问题。

// C++ 程序演示 weak_ptr 的工作方式
// 这里智能指针 P1 和 P2 都指向同一个
// 对象,但它们都不保持对象的引用。#include <iostream>
using namespace std;
// 动态内存管理库
#include <memory>class Rectangle {int length;int breadth;public:Rectangle(int l, int b){length = l;breadth = b;}int area() { return length * breadth; }
};int main()
{// 智能指针shared_ptr<Rectangle> P1(new Rectangle(10, 5));// 创建 weak_ptrweak_ptr<Rectangle> P2(P1);cout << P1->area() << endl;cout << P1.use_count() << endl;return 0;
}
50
1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/42014.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IDEA工具使用之启动项目失败且无日志打印

IDEA工具使用之启动项目失败且无日志打印 问题描述原因分析解决方案方案一&#xff1a;使用类路径缩短方案&#xff08;推荐&#xff09;方案二&#xff1a;修改启动配置 总结 问题描述 概述 新拉取的项目&#xff0c;基于IDEA本地调试启动失败&#xff0c;控制台也没有跳转打…

GC overhead limit exceeded---Java 虚拟机 (JVM) 在进行垃圾回收内存量非常少解决

背景&#xff1a; 我正在跑一个数据处理较为复杂的程序。然后调试了很多遍&#xff0c;出现了GC问题&#xff0c;如下图bug. GC overhead limit exceeded-这个bug错误通常表示 Java 虚拟机 (JVM) 在进行垃圾回收时花费了过多的时间&#xff0c;并且回收的内存量非常少。…

SAP GUI Script for C# SAP脚本开发快速指南与默认主题问题

SAP GUI Script for C# 快速指南 SAP 脚本的快速使用与设置. 解决使用SAP脚本执行后,默认打开的SAP是经典主题的问题 1. 解决默认主题问题 如果您使用的是SAP GUI 740,并遇到无法打开对话框的问题,请先将主题设置为经典主题(Classic Theme),应用更改后重新打开SAP GUI …

测试用例`

1.什么是测试用例 测试⽤例&#xff08;Test Case&#xff09;是为了实施测试⽽向被测试的系统提供的⼀组集合&#xff0c;这组集合包含&#xff1a;测试环境、操作步骤、测试数据、预期结果等要素. 2.测试用例的万能公式(重点) 设计测试⽤例的万能公式&#xff1a; 功能测试界…

【深度学习】【目标检测】【OnnxRuntime】【C++】YOLOV5模型部署

【深度学习】【目标检测】【OnnxRuntime】【C】YOLOV5模型部署 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】【目标检测】【OnnxRuntime】【C】YOLOV5模型部署前言Windows平台搭建依赖环境模型转换--pytorch转onnxONNXRuntime推…

Qt:QWebEngineView显示网页失败

今天在新电脑搭建qt开发环境&#xff0c;在运行程序时发现通过QWebEngineView显示的html失败&#xff0c;同样的代码在旧电脑上没有这个问题 分析过程 &#xff08;1&#xff09;qt出现如下信息提示 [21296:12076:0325/161831.084:ERROR:platform_handle_in_transit.cc(34)] …

第十六届蓝桥杯模拟二(串口通信)

由硬件框图可以知道我们要配置LED 和按键 一.LED 先配置LED的八个引脚为GPIO_OutPut,锁存器PD2也是,然后都设置为起始高电平,生成代码时还要去解决引脚冲突问题 二.按键 按键配置,由原理图按键所对引脚要GPIO_Input 生成代码,在文件夹中添加code文件夹,code中添加fun.…

uni-app页面怎么设计更美观

顶部 页面最顶部要获取到手机设备状态栏的高度&#xff0c;避免与状态栏重叠或者被状态栏挡住 // 这是最顶部的父级容器 <view :style"{ paddingTop: ${statusBarHeight extraPadding}px }">.... </view> export default {data() {return {statusBarH…

uniapp超简单ios截屏和上传app store构建版本方法

​ 假如使用windows开发ios的应用&#xff0c;上架的时候&#xff0c;你会发现&#xff0c;上架需要ios应用多种尺寸的ios设备的截图&#xff0c;和需要xcode等工具将打包好的ipa文件上传到app store的构建版本。 大部分情况下&#xff0c;我们的公司都没有这么多款ios设备来…

搜广推校招面经六十

soul推荐算法 一、word2vec原理 参考一篇文章入门Word2Vec 二、word2vec正负采样怎么做的、word2vec采用的loss和原理 见【搜广推校招面经四、搜广推校招面经五十二、搜广推校招面经五十七】 不太理解为啥问这么多word2vec&#xff0c;索性直接整理一遍。 三、多路召回融合…

R语言——循环

参考资料&#xff1a;学习R 在R中有三种循环&#xff1a;repeat、while和for。虽然向量化意味着我们可能并不需要大量使用它们&#xff0c;但在需要重复执行代码时&#xff0c;它们是非常有用的。 1、重复循环 R中最容易掌握的循环是repeat。它所做的事情就是反复地执行代码&a…

nginx代理前端请求

一&#xff0c;项目配置 我在 ip 为 192.168.31.177 的机器上使用 vue3 开发前端项目&#xff0c;项目中使用 axios 调用后端接口。 这是 axios 的配置&#xff1a; import axios from axios;const request axios.create({baseURL: http://192.168.31.177:8001,// 设置请求…

老外讲解用Delphi 12.3作web

老外Delphi WebStencils系列教程&#xff0c;从项目入门到发布部署&#xff0c;讲的非常详细&#xff0c;欢迎观看https://www.bilibili.com/video/BV16LZVYpETK

2.Excel :快速填充和拆分重组

一 案例1&#xff1a;快速填充 电子邮件中包含每个人的人名&#xff0c;现在要提取电子邮件中的姓名到名字列。 方法1&#xff1a;将 Nancy 复制到单元格后&#xff0c;邮件会高亮&#xff0c;然后输入A的时候系统就会知道提取名字了。 补充&#xff1a;如果第三个位置输入错误…

股票App开发第一步:如何免费快速的获取股票数据(如何免费获取金融数据)

文章目录 🌱 入坑指南:Python 如何免费获取股市数据!🌴 演示环境 🌴📒 Python 炒股数据,免费午餐,快来尝尝!📒💡 全面又亲民:数据界的“瑞士军刀”!🕰️ 专注历史:老股民的“时光机”!🌟 真正免费:开源社区的“宝藏”!🎣 实在不行,咱就自己捞!⚠…

联核防爆无人叉车:高危环境中的安全搬运守护者

联核防爆AGV无人叉车是专为易燃易爆环境设计的智能搬运设备&#xff0c;其特点、功能与应用场景均围绕“安全”与“智能”核心展开&#xff1a;联核科技官网-AGV叉车十大品牌-无人叉车厂家-自动化叉车-智能搬运码垛机器人-智能叉车系统解决方案专家 一、核心特点 防爆设计电气…

6、进程理论和简单进程创建

一、了解进程推荐看这个视频&#xff0c;很详细 1、概念 进程(Process)程序的运行过程&#xff0c;是系统进行资源分配和调度的独立单元程序的运行过程&#xff1a;多个不同程序 并发&#xff0c;同一个程序同时执行多个任务。 就需要很多资源来实现这个过程。 每个进程都有一…

Java通信

Trae - AI 原生 IDE目录 同步代码块 ​编辑 同步方法​编辑​编辑 二者对比 ​编辑 lock对象 通信 cs架构​编辑​编辑​编辑 mac地址&#xff0c;物理地址​编辑 取地址​编辑 127 0 0 1和IP 127.0.0.1和ipconfig获得的IP地址是什么关系 。127.0.0.1 和通过 ipcon…

K8S学习之基础五十八:部署nexus服务

部署nexus服务 Nexus服务器是一个代码包管理的服务器&#xff0c;可以理解 Nexus 服务器是一个巨大的 Library 仓库。Nexus 可以支持管理的工具包括 Maven &#xff0c; npm 等&#xff0c;对于 JAVA 开发来说&#xff0c;只要用到 Maven 管理就可以了。Nexus服务器作用&#x…

hackmyvm-reversteg

arp-scan -l nmap -sS -v 192.168.222.45 在源码中可以看到 根据下面的提示可以猜测117db0148dc179a2c2245c5a30e63ab0是一个图像文件 将图片下载到本地 隐写术 在两张图片上使用strings,发现有一些可打印的字符串 strings 117db0148dc179a2c2245c5a30e63ab0.jpg base64解码…