c++介绍智能指针 十二(1)
普通指针:指向内存区域的地址变量。使用普通指针容易出现一些程序错误。
如果一个指针所指向的内存区域是动态分配的,那么这个指针变量离开了所在的作用域,这块内存也不会自动销毁。动态内存不进行释放就会导致内存泄露。如果一个指针指向已经释放的区域,那么这个指针就是一个悬空指针,使用悬空指针会 造成不可预料的结果。定义了一个指针,却未初始化实际指向有效的内存区域,这个指针就成了野指针。使用野指针访问内存一般会造成段错误。
使用智能指针可以有效避免上述错误的发生。
智能指针:封装了动态对象指针的类对象。

由于智能指针是一个对象,它封装了一个指向另一个对象的指针。当智能指针离开作用域后,会被自动销毁。销毁过程中会调用析构函数,来删除封装的对象。
标准的模板库中提供了以下几种智能指针。

unique_ptr
template<
class T,
class Deletr=std::std::default_delete<T>
>class unique_ptr
T是所封装的动态对象分配类型
Deleter是unique_ptr在释放它所管理的对象时,所使用的方法。一般我们使用默认值。template<
class T,
class Deleter
>class unique_prt<T[],Deleter>
针对动态数组的特化版本。
以下是unique_ptr的常用函数。T* get(); //获得所管理对象指针
T* operator->();//重载的间接运算符调用了get函数,也返回了所管理对象的指针,这样可以使用间接成员运算符来访问所管理的对象成员了
T& operator*();//重载的解引用运算符返回所管理的对象的引用,相当于*get()函数
T* release();//接触对封装对象的管理,返回对象的指针,这个对象指针脱离unique_ptr,c成为一个普通指针,用完这个指针需要手动释放。
void reset(T* newObject);//删除原有的对象,接管新的对象
void swap(unique_ptr<T>&other);与其他的unique_Ptr对象互换。
unique_ptr与它所管理的对象是动态一对一的关系,不能有两个unique_ptr对象指向同一个地址。
创建一个unique对象的方法是
unique_ptr<A>ptr1(new A(参数))
unique_ptr<A>ptr=make_unique<A>(参数)
#include<memory>
#include<iostream>using namespace std;
class Rectangle
{
public:Rectangle(double w,double h):width(w),height(h) {}~Rectangle() { cout << "对象封装被释放" << endl; }double area(){return width * height;}
private:double width;double height;
};
int main()
{using std::unique_ptr;{unique_ptr<Rectangle>pDemo(new Rectangle(3,4));cout << pDemo->area() << endl;}
}
由于智能指针重载了间接成员运算符和解引用运算符,它们会返回智能指针所包含对象的指针或者引用,可以像使用普通指针一样使用智能指针。除了在离开当前作用域时会删除指针指向的对象,下面几种方法也会删除
unique_ptr<Rectangle>p1(new Rectangle(1, 1));
p1 = nullptr;unique_ptr<Rectangle>p1(new Rectangle(1, 1));
unique_ptr<Rectangle>p2(new Rectangle(1, 1));
p1 = move(p2);unique_ptr<Rectangle>p1(new Rectangle(1, 1));
p1.reset(new Rectangle(3, 7));
由于unique_ptrd对管理的资源具有独占性,所以unique_ptr不能被拷贝,也不能被赋值。不过可以对unique_ptr对象所管理对象所有权进行转移。
#include<memory>
#include<iostream>using namespace std;
class Rectangle
{
public:Rectangle(double w,double h):width(w),height(h) {}~Rectangle() { cout << "对象封装被释放" << endl; }double area(){return width * height;}
private:double width;double height;
};
int main()
{unique_ptr<Rectangle>p1(new Rectangle(1,3));unique_ptr<Rectangle>p2 = move(p1);cout << p2->area() << endl;}
上述代码中通过move函数p2拥有了p1对象管理权。p1包含了一个空指针。这时可以通过p2来访问它所封装的对象成员了。
unique_ptr主要适合在使用在普通指针的地方,例如使用在容器上,
struct Packet
{Packet(long id) :m_id(id) {}long m_id;char Data[1000];
};
struct Compare {bool operator()(const Packet& a, const Packet& b){return a.m_id < b.m_id;}
};
void sortValueVector(int n)
{vector<Packet>vecPacket;for (int i = 0; i < n; i++){vecPacket.push_back(Packet(rand() % n));}sort(vecPacket.begin(), vecPacket.end(), Compare());
}
用vector装入n个Packet对象,然后对他进行排序。由于容器中装入的是对象,对于这种较大的对象,排序意味着大量数据进行移动复制,这样开销很大。如果将容器中的对象改为指针 ,排序时仅涉及到指针值的复制。那么效率会高很多。如下代码
struct Packet
{Packet(long id) :m_id(id) {}long m_id;char Data[1000];
};
struct Compare {bool operator()(const Packet* pA, const Packet* pB){return pA->m_id < pB->m_id;}
};
void sortValueVector(int n)
{vector<Packet*>vecPacket;for (int i = 0; i < n; i++){vecPacket.push_back(new Packet(rand() % n));}sort(vecPacket.begin(), vecPacket.end(), Compare());
}
使用指针的缺点是需要使用专门的代码对指针维护,当删除,替换时,需要释放不再使用的指针对象, 如果出现异常,提前返回等情况,容易造成内存泄露。如果将容器中的指针替换成unique_ptr,不仅获得接近普通性能的智能指针,还实现了内存资源的自动释放,不会出现意外的内存泄露情况。
下面这段代码中针对compare 类针对对象,指针,智能指针,三种情况下,排序所用时间
#include<memory>
#include<iostream>
#include<vector>
#include<algorithm>
#include<chrono>
using namespace std;
using namespace std::chrono;
struct Packet
{Packet(long id) :m_id(id) {}long m_id;char Data[1000];
};
struct Compare {bool operator()(const Packet& a, const Packet& b){return a.m_id < b.m_id;}bool operator()(const Packet* pA, const Packet* pB){return pA->m_id < pB->m_id;}//template<template<typename>typename SmartPtr>bool operator()(const unique_ptr<Packet>& pA, const unique_ptr<Packet>& pB){return pA->m_id < pB->m_id;}
};
class AutoToTimer {
private:high_resolution_clock::time_point startTime;string description;
public:AutoToTimer(const char* desc) :description(desc) {startTime = high_resolution_clock::now();}~AutoToTimer(){high_resolution_clock::time_point endTime = high_resolution_clock::now();auto duration = duration_cast<chrono::microseconds>(endTime - startTime).count();cout << description << ":" << duration << "ms" << endl;}
};
void sortValueVector(vector<int>ids)
{vector<Packet>vecPacket;for (auto id : ids){vecPacket.push_back(Packet(id));}{ AutoToTimer autoTimer("sortValueVector");sort(vecPacket.begin(),vecPacket.end(),Compare());}
}void sortPointVector(vector<int>ids)
{vector<Packet*>vecPacket;for (auto id : ids){vecPacket.push_back(new Packet(id));}{AutoToTimer autoTimer("sortPointPtr");sort(vecPacket.begin(), vecPacket.end(), Compare());}
}
template<typename SmartPtr>
void sortSmartPtrVector(vector<int>ids)
{vector<SmartPtr>vecPacket;for (auto id : ids){vecPacket.push_back(SmartPtr(new Packet(id)));}{AutoToTimer autoTime("sortUniquePtrVector");sort(vecPacket.begin(),vecPacket.end(),Compare());}
}
int main()
{int n = 100000;vector<int>randomId{ n,0 };for (int i = 0; i < n; i++){randomId.push_back(rand() % 100000);}sortValueVector(randomId);sortPointVector(randomId);sortSmartPtrVector<unique_ptr<Packet>>(randomId);
}
打印结果
相关文章:
c++介绍智能指针 十二(1)
普通指针:指向内存区域的地址变量。使用普通指针容易出现一些程序错误。 如果一个指针所指向的内存区域是动态分配的,那么这个指针变量离开了所在的作用域,这块内存也不会自动销毁。动态内存不进行释放就会导致内存泄露。如果一个指针指向已…...
Vue的scoped原理是什么?
scoped的工作原理 当在 <style> 标签上使用 scoped 属性时,Vue 会为当前组件的每个元素添加一个唯一的 data-v-xxxxxx 属性,并将样式规则中的选择器修改为包含该属性的形式。 编译阶段: 在编译 .vue 文件时,Vue 的编译器…...
大白话解释 React 中高阶组件(HOC)的概念和应用场景,并实现一个简单的 HOC。
高阶组件(HOC)的概念 在 React 里,高阶组件(Higher-Order Component,简称 HOC)就像是一个“超级工厂函数”。它本身是一个函数,而且这个函数接收一个组件作为参数,然后返回一个新的…...
深入浅出C++ STL:统领STL全局
深入浅出C STL:统领STL全局 深入浅出C STL:统领STL全局github主页地址前言一、STL的前世今生1.1 什么是STL?1.2 STL版本演进 二、STL六大核心组件详解2.1 容器(Containers)容器性能对照表 2.2 算法(Algorit…...
k8s面试题总结(十五)
1.如何使用Kubernetes进行多环境部署(如开发,测试和生产环境)? 使用命名空间(namespaces): 命名空间是用于逻辑隔离和资源分组的一种方式,可以为每个环境创建单独的命名空间。 2.使…...
Appium等待机制--强制等待、隐式等待、显式等待
书接上回,Appium高级操作--其他操作-CSDN博客文章浏览阅读182次,点赞6次,收藏7次。书接上回Appium高级操作--从源码角度解析--模拟复杂手势操作-CSDN博客。https://blog.csdn.net/fantasy_4/article/details/146162851主要讲解了Appium的一些…...
Vue源码深度解析:从2.x到3.x的架构演进与核心原理剖析
Vue源码深度解析:从2.x到3.x的架构演进与核心原理剖析 一、框架演变:从Vue2到Vue3的跨越 1.1 革命性升级 Vue3的发布标志着前端框架进入新纪元,其核心改进体现在三个方面: 性能飞跃:包体积减少41%,初始…...
计算机视觉cv2入门之图像的读取,显示,与保存
在计算机视觉领域,Python的cv2库是一个不可或缺的工具,它提供了丰富的图像处理功能。作为OpenCV的Python接口,cv2使得图像处理的实现变得简单而高效。 示例图片 目录 opencv获取方式 图像基本知识 颜色空间 RGB HSV 图像格式 BMP格式 …...
前置机跟服务器的关系
在复杂的IT系统架构中,前置机与服务器的协同配合是保障业务高效、安全运行的关键。两者的关系既非简单的上下级,也非独立个体,而是通过功能分层与职责分工,构建起一套既能应对高并发压力、又能抵御安全风险的弹性体系。 在当今复…...
【Vue】el-dialog的2种封装方法(父子组件双向通信),$emit触发父事件/.sync修饰符双向绑定
🤵 作者:coderYYY 🧑 个人简介:前端程序媛,目前主攻web前端,后端辅助,其他技术知识也会偶尔分享🍀欢迎和我一起交流!🚀(评论和私信一般会回!!) 👉 个人专栏推荐:《前端项目教程以及代码》 前言 在现代Vue.js开发中,el-dialog组件作为ElementUI库中的一个…...
CCF CSP 第30次(2023.09)(1_坐标变换_C++)(先输入再计算;边输入边计算)
CCF CSP 第30次(2023.09)(1_坐标变换_C) 题目描述:输入格式:输出格式:样例输入:样例输出:样例解释:子任务:解题思路:思路一࿰…...
【QT】事件系统入门——QEvent 基础与示例
一、事件介绍 事件是 应用程序内部或者外部产生的事情或者动作的统称 在 Qt 中使用一个对象来表示一个事件。所有的 Qt 事件均继承于抽象类 QEvent。事件是由系统或者 Qt 平台本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候&…...
5-27 临摹大师-IP-Adapter
前言: 前一节我们主要介绍ControlNet中如何对黑白照片进行上色 主要介绍ControlNet中的IP-Adapter。这个也是一种类似的风格借鉴,类似Reference的能力。 当然IP-Adapter有两点或许可以吸引我们,一个是国人腾讯公司制作的。另一个在速度和效…...
Spring MVC面试题(一)
1.什么是Spring MVC? 全称为Model View Controller,Spring MVC是Spring的一个模块,基于MVC架构模式的一个框架 2.Spring MVC优点? 1.可用各种视图技术,不仅限于JSP 2.支持各种请求资源映射策略 3. Spring MVC工作原…...
Unity开发的抖音小游戏接入抖音开放平台中的流量主(抖音小游戏接入广告)
前言:作者在进行小游戏审核版本的过程中,碰到了下列问题,所以对这个抖音小游戏接入广告研究了下。 还有就是作者的TTSDK版本号是6.2.6,使用的Unity版本是Unity2022.3.29f1,最好和作者的两个版本号保持一致,因为我发现TTSDK旧版的很多函数在新版中就已经无法正常使用了,必…...
统一 Elastic 向量数据库与 LLM 功能,实现智能查询
作者:来自 Elastic Sunile Manjee 利用 LLM 功能进行查询解析,并使用 Elasticsearch 搜索模板,将复杂的用户请求转换为结构化的、基于模式的搜索,从而实现高精度查询结果。 想象一下,你在搜索“距离 Belongil Beach 25…...
[操作系统] 学校课程关于“静态优先级抢占式调度“作业
今天我们来分享两道题目哈, 学校弄得题目. T1: 静态优先级, 抢占式(1为高优先级) 图解: 以下是静态优先级抢占式调度的解题过程和结果: 解题思路: 优先级规则: 数值越小优先级越高。新进程到达时,若其优先级高于当前运行进程&…...
【SpringBoot】MD5加盐算法的详解
目录 一、什么是加盐算法 二、如何实现加盐算法 2.1 加盐算法代码实现 2.2 注册页面中进行密码加盐 2.3 登录页面进行加盐的解密 2.4 注册和登录 一、什么是加盐算法 加盐算法是一种用于增强密码安全性的技术。这种技术通过在密码存储过程中添加一个随机生成的盐值&…...
kotlin与MVVM结合使用总结(一)
一、Kotlin 与 MVVM 结合的核心优势 代码简洁性 数据类(data class)简化 Model 层定义,自动生成equals/hashCode/toString扩展函数简化 View 层逻辑(如点击事件扩展)lateinit/by lazy优化 ViewModel 属性初始化 异步处…...
累计完工数量达到了xxxx超过了最大可完工数量xxxx
之前解决过一次,没有记录下来,不记得发生什么事情。又浪费几个小时去分析问题。这次的经历有点痛苦,碰上多表关连数据的勾稽。分析是河南用户的非法操作造成的。没有领料记录入不了库,跨月了。财务要求删单处理。删单之后…...
飞鸟与鱼不同路
看,好美的太阳。 正是因为有人看才会觉得美,若无人问津,美又从何而来。 嘿嘿,今天提出辞去综合教研室主任一职,不想在这个管理上废时间啦~ 把时间用来考试.........用来做自己的事情,花在自己的身上&…...
若依RuoYi-Cloud-Plus微服务版(完整版)前后端部署
一.目标 在浏览器上成功登录进入 二.源码下载 后端源码:前往Gitee下载页面(https://gitee.com/dromara/RuoYi-Cloud-Plus)下载解压到工作目录。 前端源码: 前往Gitee下载页面(https://gitee.com/JavaLionLi/plus-ui)下载解压到工作目录。 文档地址&a…...
【redis】list类型:基本命令(下)
文章目录 LLENLREMLTRIMLSET阻塞版本命令BLPOP 和 BRPOP区别使用方式 命令小结内部编码 LLEN 获取 list 的长度 语法: LLEN key时间复杂度: O ( 1 ) O(1) O(1)返回值: list 长度 LREM 删除 count 个 key 中的元素 语法: LREM…...
【数据挖掘】知识蒸馏(Knowledge Distillation, KD)
1. 概念 知识蒸馏(Knowledge Distillation, KD)是一种模型压缩和知识迁移技术,旨在将大型复杂模型(称为教师模型)中的知识传递给一个较小的模型(称为学生模型),以减少计算成本&…...
VSCode 搭建C++编程环境 2025新版图文安装教程(100%搭建成功,VSCode安装+C++环境搭建+运行测试+背景图设置)
名人说:博观而约取,厚积而薄发。——苏轼《稼说送张琥》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、VScode下载及安装二、安装 MinGW-w64 工具链三、Windows环境变量配置四、检查 M…...
Ubuntu24.04 LTS 版本 Linux 系统在线和离线安装 Docker 和 Docker compose
一、更换软件源并更新系统 在 Ubuntu 24.04 LTS 中,系统引入了全新的软件源配置格式。现在的源配置文件内容更加结构化且清晰,主要包含了软件类型 (Types)、源地址 (URIs)、版本代号 (Suites) 以及组件 (Components) 等信息。 # cat /etc/apt/sources.li…...
从 pip 到 Poetry:开启高效 Python 包管理新时代
目录 从 pip 到 Poetry:开启高效 Python 包管理新时代 一、pip 与 Poetry 的基本区别 二、Poetry 相对于 pip 的优势 1. 依赖管理与版本锁定 2. 内置虚拟环境管理 3. 统一的项目管理流程 4. 精细的依赖解析器 5. 更友好的 CLI 工具 三、如何快速上手 Poetry…...
MTK Android12 最近历史任务 最左侧的清除历史任务改到页面底部
Android最近历史任务页面 -清除所有- 功能按钮放到底部 文章目录 需求需求原因 修改的核心文件实现方案最近历史任务基本UI结构了解代码实现思路实现方案RecentsViewTaskOverlayFactory在overview_actions_containerOverviewActionsView 实际效果 总结 需求 最近历史任务重&am…...
TCP协议支持全双工原因TCP发送接收数据是生产者消费者模型
一、TCP支持全双工的原因 TCP协议支持全双工,即使用TCP协议进行通信时,服务端和客户端可以同时进行数据的发送和接收,互不干扰,实现同时双向传输数据。 这是因为使用TCP协议通信时,读写套接字的文件描述符既用来发送…...
文件操作2
7. ⽂件读取结束的判定 7.1 被错误使用的 feof 牢记:在文件读取过程中,不能用 feof 函数的返回值直接来判断文件的是否结束。 feof 的作用是:当文件读取结束的时候,判断读取结束的原因是否是:遇到文件尾结束。 1. …...
