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);
}

打印结果

 

 

 

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

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

相关文章

亚马逊COSMO算法解读:新搜索时代的流量分配与DeepBI AI驱动的智能优化策略

亚马逊COSMO算法的推出&#xff0c;标志着其搜索和推荐系统进入了智能化、个性化的新阶段。该算法通过分析用户购物习惯、搜索历史、浏览行为等数据&#xff0c;为买家提供精准推荐&#xff0c;同时对卖家的运营策略提出了更高的要求。在这一背景下&#xff0c;AI驱动的DeepBI能…

C++编译问题——1模板函数的实现必须在头文件中

今天编译数据结构时&#xff0c;遇见一个编译错误 假设你有一个头文件 SeqList.h 和一个源文件 SeqList.cpp。 SeqList.h #ifndef SEQLIST_H #define SEQLIST_H#include <stdexcept> #include <iostream>template<typename T> class SeqList { private:sta…

安卓实现魔改版 CRC32 算法

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 关于 CRC32 算法介绍可以参考这篇文章&#xff1a;常用加解密算法介绍 标准 CRC32 算法 创建 crc32.cpp&#xff0c;使用 C 实现标准 CRC32 算法 #include …

OneHot编码与OrdinalEncoder编码的区别与应用解析

OneHot编码和OrdinalEncoder编码是两种常见的类别特征编码方式&#xff0c;它们的主要目的是将类别数据转换为数值数据&#xff0c;以便机器学习算法能够处理。下面是对这两种编码方式的详细解释和比较&#xff1a; 一、OneHot编码 1. 定义&#xff1a; OneHot编码是一种将每…

python离线安装

Python Releases for Windows | Python.org 下载包地址widows一般是64bit的包 下载完成后双击&#xff0c;在弹出的首个页面会看到下面的图 第一步&#xff1a;建议手动安装 第二步&#xff1a;一定要勾选把版本加入到Path路径 然后就是无脑下一步&#xff0c;到这一步就可…

Web开发-PHP应用文件操作安全上传下载任意读取删除目录遍历文件包含

知识点&#xff1a; 1、安全开发-原生PHP-文件安全操作 2、安全开发-原生PHP-上传读取删除包含等 3、安全开发-原生PHP-代码审计文件安全 一、演示案例-WEB开发-文件安全-上传下载读取 文件上传 $_FILES&#xff1a;PHP中一个预定义的超全局变量&#xff0c;用于在上传文件时…

自然语言处理:文本聚类

介绍 大家好&#xff0c;博主又来和大家分享自然语言处理领域的知识了。今天给大家分享的内容是自然语言处理中的文本聚类。 文本聚类在自然语言处理领域占据着重要地位&#xff0c;它能将大量无序的文本按照内容的相似性自动划分成不同的类别&#xff0c;极大地提高了文本处…

JavaScript 运算符详解

引言 在 JavaScript 编程中&#xff0c;运算符是用于对数据进行操作的特殊符号。通过使用运算符&#xff0c;我们可以实现各种计算、比较和逻辑判断等功能。JavaScript 中的运算符种类丰富&#xff0c;涵盖了算术、比较、逻辑、赋值等多个方面。下面将详细介绍各类运算符及其使…

基于javaweb的SpringBoot个人健康管理系统小程序微信小程序设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

责任链模式的C++实现示例

核心思想 责任链模式是一种行为设计模式&#xff0c;允许多个对象都有机会处理请求&#xff0c;从而避免请求的发送者与接收者之间的耦合。请求沿着处理链传递&#xff0c;直到某个对象处理它为止。 解决的问题 ​解耦请求发送者与处理者&#xff1a;请求的发送者无需知道具…

Java 无 GUI 浏览器:HtmlUnit 入门及实战 [特殊字符]

文章目录 HtmlUnit 入门功能简介入门案例更多功能HtmlUnit 实战需求页面分析编码参考⭐ 本文目标: HtmlUnit 框架入门HtmlUnit 框架实战:实现 HtmlUnit 访问 Web 页面,并实现 Web 页面按钮点击,同时获取到下载的文件。HtmlUnit 入门 🚀 官网:https://htmlunit.sourcefo…

微软 NativeAOT

微软Native AOT&#xff08;Ahead-Of-Time&#xff09;是.NET平台中一种新的运行模式&#xff0c;它直接将IL&#xff08;Intermediate Language&#xff0c;中间语言&#xff09;代码编译为目标平台的机器码发布&#xff0c;与JIT&#xff08;Just-In-Time&#xff0c;即时编译…

Vue项目搜索引擎优化(SEO)终极指南:从原理到实战

文章目录 1. SEO基础与Vue项目的挑战1.1 为什么Vue项目需要特殊SEO处理&#xff1f;1.2 搜索引擎爬虫工作原理 2. 服务端渲染&#xff08;SSR&#xff09;解决方案2.1 Nuxt.js框架实战原理代码实现流程图 2.2 自定义SSR实现 3. 静态站点生成&#xff08;SSG&#xff09;技术3.1…

Java 枚举

一、简介 Java 枚举是一种强大的工具&#xff0c;其本质上是一个继承自 java.lang.Enum 的类&#xff0c;用于定义一组固定的常量&#xff0c;每个枚举常量都是该枚举类的一个实例。枚举不仅提供了类型安全性&#xff0c;还可以像普通类一样拥有字段、方法和构造函数。枚举的使…

CentOS7安装DNS服务器bind

文章目录 安装DNS服务设置配置文件自定义域名解析完整配置 需求是公司内网服务器无法连接外网&#xff0c;需要在本地搭建DNS服务&#xff0c;这样物理机器迁移到内网后&#xff0c;通过域名解析访问服务 DNS服务器 172.25.14.215 ip域名172.25.14.216mysql.server172.25.14.2…

DFS刷题(25.3.13)

题目1——烤鸡 题目描述 题解 这是一个简单的暴搜题目&#xff0c;由于一共由10种配料&#xff0c;每种配料可以放1到3克&#xff0c;因此只需要用dfs对每种配料放入的质量进行暴力搜索即可&#xff0c;如果放入的配料质量之和等于题目给出的美味程度 n n n&#xff0c;记录一…

C#中除了Dictionary,List,HashSet,HashTable 还有哪些可以保存列表的数据类型?

在 C# 中&#xff0c;除了 Dictionary、List、HashSet 和 Hashtable 之外&#xff0c;还有许多其他可以保存列表或集合类型的数据结构&#xff0c;具体包括以下几类&#xff1a; &#x1f4cc; 数组类 1. Array&#xff08;数组&#xff09; 固定长度&#xff0c;性能高&…

《Python实战进阶》第21集:数据存储:Redis 与 MongoDB 的使用场景

第21集&#xff1a;数据存储&#xff1a;Redis 与 MongoDB 的使用场景 摘要 在现代应用开发中&#xff0c;数据存储的选择直接影响系统的性能、扩展性和成本。Redis 和 MongoDB 是两种极具代表性的数据库技术&#xff0c;它们分别擅长解决不同场景下的问题。本文将深入探讨 Re…

三视图转stl导出 空心面片体 networkx shapely triangle numpy-stl

from shapely.geometry import Polygon import triangle from shapely.ops import unary_union from stl import mesh import numpy as np from collections import defaultdict from 三维投影线段寻找 import get_adjusted_clusters,get_clusters,get_intersect_lines import …

大摩闭门会:250312 学习总结报告

如果图片分辨率不足&#xff0c;可右键图片在新标签打开图片或者下载末尾源文件进行查看 本文只是针对视频做相应学术记录&#xff0c;进行学习讨论使用