智能指针原理剖析(一):auto_ptr、unique_ptr

2023-11-14

通过常规指针管理动态内存的难点及缺点:

(1)忘记释放动态内存: 使用new/malloc分配动态内存时,需要使用delete/free手动释放内存,但程序员容易忘记释放内存,从而产生内存泄露;
(2)动态内存释放时机不对: 在尚有指针引用内存的情况下,程序员释放了内存,从而产生空悬指针。典型的案例就是:假设在多线程编程中,线程A、B中分别有指针p1、p2指向对象object,若某个时刻线程A通过p1将object销毁了(释放了object占有的内存),那么线程B中的p2引用object就会产生内存错误。

程序员手动管理动态内存的困难,促使了智能指针的产生。智能指针可以自动隐式地释放动态内存,大大减少了内存错误,方便了动态内存的管理。有很多学者都对智能指针的源码进行了剖析,我将结合源码剖析分两篇博客对auto_ptr、unique_ptr、shared_ptr、weak_ptr依次进行总结。

auto_ptr根据博客https://blog.csdn.net/yanglingwell/article/details/56011576的源码剖析进行原理总结。

auto_ptr

auto_ptr中只有一个私有成员变量,即指向_Ty类型对象的指针_Myptr。

1、构造函数

auto_ptr有三种构造方式,一是通过传入指针来初始化_Myptr,二是通过同类型的auto_ptr对象来拷贝构造,但会利用release函数将原对象指针置为空,三是通过不同类型的auto_ptr对象来拷贝构造,也会利用release函数置空原对象指针。

2、拷贝赋值函数

拷贝赋值函数有两种,一是利用相同类型的auto_ptr对象进行拷贝赋值,二是利用不同类型的auto_ptr对象进行拷贝赋值。二者都会用release函数置空传入的对象指针并返回新的对象,再用reset函数赋值自身的指针成员_Myptr。

3、重载函数

auto_ptr本质上是一个类,为了让auto_ptr对象有像指针一样的行为,就需要重载*运算符和->运算符,这样auto_ptr对象就有了指针操作。
例如:
class A
{
public:
int m_A;
int m_B;
}
auto_ptr< int > p(new A(a,b));
“p->”可以访问A中的成员,“*p”可以得到指向对象的首地址。

4、析构函数

auto_ptr的析构函数比较简单,仅释放指针成员_Myptr持有的资源,即delete _Myptr。auto_ptr的析构函数保证了auto_ptr对象在生命期结束销毁时,可以自动释放其指向的内存资源,从而避免了内存泄露。

5、auto_ptr总结

auto_ptr是智能指针的初始版本,其设计原则为“严禁一物二主”。auto_ptr的设计中存在不合理之处,即提供了拷贝构造、拷贝赋值操作,却会置空原对象指针成员,这样显得拷贝毫无意义,而且在使用中极易误操作原对象,从而出现错误且很难发现。因此,现在的标准库已经不推荐使用auto_ptr了,但是可以作为智能指针的入门学习。

unique_ptr根据https://blog.csdn.net/qq_28114615/article/details/100528326的源码剖析进行原理总结。

unique_ptr

unique_ptr是auto_ptr的进化版本,也是一种独占式指针,但是合理性更强。
unique_ptr禁止了拷贝构造和赋值重载,但是比auto_ptr多了一个删除器。

1、_Unique_ptr_base

_Unique_ptr_base是unique_ptr的父类,用于管理删除器
_Unique_ptr_base是一个类模板,有两种定义,一种是删除器为空的定义,一种是删除器不为空的定义。
删除器为空时,_Unique_ptr_base只有一个成员_Myptr(pointer类型),删除器不为空时,_Unique_ptr_base有两个成员_Myptr(pointer类型)和_Mydel(_Dx类型)。其中,_Myptr是管理的指针成员,_Mydel是删除器实例。删除器为空时,使用的是默认的删除器default_delete。

2、构造函数

unique_ptr的构造函数主要针对pointer类型的指针成员_Myptr。
(1)无参构造:用临时构造的pointer类型构造_Unique_ptr_base,初始化指针成员_Myptr为NULL;
(2)有参构造:有两种,一是传入pointer类型的指针对象_Ptr来构造_Mybase,二是传入_Ptr和删除器实例来构造;
(3)移动构造:用另一个相同类型或不同类型的unique_ptr对象、以及auto_ptr对象来右值构造,从而实现了资源的拥有权的转移,保证了资源永远只有一个拥有者,符合独占式设计原则 。

3、移动赋值函数

unique_ptr的赋值函数也是利用右值重载的的原则,从而实现所有权的转移,符合独占式设计原则。

4、资源交换函数swap

unique_ptr利用swap函数实现两个相同类型unique_ptr对象所管理资源的所有权交换。

5、重载函数

与auto_ptr一样,unique也提供了*运算符和->运算符的重载函数,从而使unique_ptr有指针的行为。

6、析构函数

当unique_ptr对象生命期结束时,会在析构函数中调用删除器,删除器就会释放所管理的内存资源。

7、unique_ptr总结

unique_ptr的功能与auto_ptr类似,是一种独占式智能指针。unique_ptr的实现比较复杂,但是合理性更强。unique_ptr利用移动构造函数和移动赋值函数来实现资源的转移,即通过右值引用方式来销毁原对象,并把内存资源的所有权转移给新对象。原对象销毁后,程序员将无法再对原对象进行操作,这也避免了auto_ptr的缺点,因此,现在C++标准库中推荐使用unique_ptr。

unique_ptr与auto_ptr的另一个不同点是:auto_ptr直接在析构函数中释放内存资源;unique_ptr中定义了一个删除器,会在析构函数中调用删除器,再通过删除器释放资源。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

智能指针原理剖析(一):auto_ptr、unique_ptr 的相关文章

  • C++ STL 映射,std::pair 作为键

    这就是我通过地图定义的方式 std map
  • 如何在 Google Mock 中使用可选参数来模拟方法?

    如何使用可选参数模拟方法谷歌模拟 例如 class A public void set enable bool enabled true class MockA public A MOCK METHOD1 set enable void b
  • 使用c#在mac上启动外部进程

    我成功地使用 System Diagnostics Process Start 在 Windows 上启动我的外部单声道可执行文件 然而在mac上却失败了 我没有收到任何错误 只是什么也没发生 我尝试按以下方式进行操作 System Dia
  • R 包与 Rcpp 的链接错误:“未定义符号:LAPACKE_dgels”

    我正在创建一个 R 包 lapacker 以使用 R API 头文件 R ext Lapack h 为 R 提供和使用的内部 LAPACK 库 仅具有双精度和双复数 提供 C 接口 源代码 https github com ypan1988
  • 为什么 xcode IDE 认为 `friend` 是保留字

    我一直在开发一个个人项目 并在我创建的新类中包含以下代码 property readonly getter isFriend BOOL friend 它似乎没有任何问题 当我构建它时 它可以编译得很好 但是当我们在xcode IDE看起来像
  • 如何查看每秒更新的图表中的最后 10 个数据点?

    我有这个代码 private void timer Tick object sender EventArgs e timer Stop for int i 0 i lt TOTAL SENSORS i DateTime d DateTime
  • .Net 支持柯里化泛型吗?

    假设我们有一个嵌套的泛型类 public class A
  • 将 JavaScript 引擎嵌入到 .NET 中 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 只是想知道是否有人尝试过将任何 js 引擎嵌入并实际集成到 net 环境中 我可以找到并实际使用 经过L
  • 来自同一基模板类的 C++ 重写函数,具有多重继承不明确的函数调用

    我需要打电话init int iNumber 从基类派生的函数 基类 h pragma once include stdafx h template
  • 向客户端发送状态码 500 时页面未呈现

    我有一个页面 通用处理程序 我想在该页面上向客户端返回状态代码 500 以指示出现问题 我这样做 Response StatusCode 500 Response StatusDescription Internal Server Erro
  • 如何使用 itextsharp 更改 PDF 公式的按钮图标?

    我目前正在尝试使用 itextsharp 填写预定义的表单 除了添加图像之外 一切正常 这之前已经在 Adob e 的 FDF 工具包中运行过 该工具包已编译为 NET 1 1 这不再适用于 NET 4 0 我改用了 itextsharp
  • 括号内声明的对象的范围

    如果我声明一个这样的对象 void main myclass objectA anotherclass true true 0 即 我通过直接调用后者的构造函数来创建一个 objectA 和另一个对象 anotherclass anothe
  • Qt - 添加超链接到对话框

    有没有办法在 Qt 对话框中添加可点击的超链接 IE 它应该看起来像一个超链接 蓝色文本 当您单击它时 它应该在浏览器中打开该超链接 像这样的东西 Use QLabel setOpenExternalLinks bool 并在标签上设置文本
  • ArrayList 有什么问题?

    最近我问了一个关于 SO 的问题 其中提到了可能使用 c ArrayList 来解决问题 有人评论说使用数组列表不好 我想了解更多有关此的信息 我以前从未听说过关于数组列表的这种说法 有人可以带我了解使用数组列表可能出现的性能问题吗 C n
  • 在 C 中运行 setuid 程序的正确方法

    我有一个权限为4750的进程 我的Linux系统中存在两个用户 root 用户和 appz 用户 该进程继承以 appz 用户身份运行的进程管理器的权限 我有两个基本惯例 void do root void int status statu
  • C 中的等效 plpgsql 触发器

    我有一个 PostgreSQL 9 0 服务器 并且在某些表上使用继承 因此我必须通过如下触发器模拟外键 CREATE OR REPLACE FUNCTION othertable before update trigger RETURNS
  • 将“C# 友好类型”名称转换为实际类型:“int” => typeof(int)

    我想得到一个System Type给定一个string指定 原始 类型C 友好名称 基本上与 C 编译器读取 C 源代码时的方式相同 我觉得描述我所追求的最好方式是单元测试的形式 我希望存在一种通用技术 可以使以下所有断言通过 而不是尝试对
  • 如何正确处置注入的DLL线程?

    我将一个 DLL 注入到目标进程中 以在玩 MMORPG 时充当助手 当前功能将按键转换为鼠标点击 因为 MMORPG 要求用户移动鼠标才能实现某些功能 这是我所鄙视的 假设我出于某种原因想要取消注入 DLL 我该怎么做呢 这个方法干净吗
  • C# 使用 .Equals() 比较两个 double

    我使用 ReShaper 当我用 比较两个双精度值时 它建议我应该使用 Math 具有公差的 ABS 方法 看 https www jetbrains com help resharper 2016 2 CompareOfFloatsByE
  • Web 和 winforms 的 .Net 身份验证

    我有一个为客户端构建的 ASP NET Web 应用程序 它使用默认的 ASP NET 表单身份验证 他们现在请求一个能够 与 Web 应用程序一起工作的桌面 WinForms 应用程序 我已经创建了 Web 服务来访问他们想要从 Web

随机推荐

  • STM32学习笔记---TFT-LCD

    一 常见显示器介绍 1 显示器分类 显示器属于计算机的 I O 设备 即输入输出设备 它是一种将特定电子信息输出到屏幕上再反射到人眼的显示工具 常见显示器有三类 CRT显示器 LCD液晶显示器 LED点阵显示器 1 1 CRT显示器
  • Golang基础(指针)

    一 变量地址 变量本质就是内存中一块数据的标记 把值存储到变量中实质是把值存储到内存中 每次对变量重新赋值就是在修改变量地址中的内容 在Go语言中可以通过 变量名 获取到变量地址值 重新创建一个非引用型变量 即使是把已有变量直接赋值给新变量
  • Python爬虫实战之电影爬取过程

    俗话说 兴趣所在 方能大展拳脚 so结合兴趣的学习才能事半功倍 更加努力专心 apparently本次任务是在视频网站爬取一些好看的小电影 地址不放 狗头保命 只记录过程 实现功能 从网站上爬取采用m3u8分段方式的视频文件 对加密的 ts
  • 常见的开源协议有哪些

    开源软件 Open source software 的源代码对有追求的程序员来说是一无尽的宝藏 此外正确的使用开源软件 可以提高开发软件时的效率 提升软件质量 但是在使用和借鉴开源软件的时候 我们不得不关心一下它对使用者的诸多限制 比较常见
  • vscode怎么使用live server

    步骤 1 点击左边活动栏最下面的插件按钮 2 在输入框搜索live server插件 大概输完 live 下面就出现了 3 安装live server插件 4 此时右下角状态栏会出现 go live 图解 像这样子 就可以了
  • openstack创建域、项目、用户、角色报错

    报错出现 An unexpected error prevented the server from fulfilling your request HTTP 500 1 创建项目service openstack project crea
  • URL传参

    传递多个参数 URL report asp ID 123 paramterName2 456 kehu Server UrlEncode 客户名 取值 Request paramterName eg Request ID 提交表单的时候 会
  • React扩展知识

    目录 setState lazyLoad Hooks 1 React Hook Hooks是什么 2 三个常用的Hook 3 State Hook 4 Effect Hook Ref Hook 代码示例 Fragment Context 组
  • js对象常用方法

    for in遍历对象 let user name John age 30 isAdmin true for let key in user keys alert key name age isAdmin 属性键的值 alert user k
  • Linux下安装hbase

    系统环境 银河麒麟V10 JDK8 Hbase2 2 7 一 安装JDK 1 下载地址 http www oracle com technetwork java javase downloads jdk8 downloads 2133151
  • css 水平垂直居中的几种常见方式

    下面是几种常见的水平垂直居中方式 可在不同情形下方便采用不同的方式 html div class box div class content div div 共同的css content width 50 height 50 margin
  • C++中的STL中map用法详解

    map用法详解 Map是STL的一个关联容器 它提供一对一的数据处理能力 由于这个特性 它完成有可能在我们处理一对一数据的时候 在编程上提供快速通道 这里说下map内部数据的组织 map内部自建一颗红黑树 一 种非严格意义上的平衡二叉树 这
  • Python 日志-装饰器

    参考文章 程序员小谭 自动化项目实战08 日志 插入脚本展示 代码实现 def write case log def wrapper func func wraps func 防止函数名称与注释文档被重写 def inner func ar
  • listview 弹窗效果实现 +类似qq的滑动删除效果

    需求 点击ListItem 后 在item上弹出一个类似PopupWindows 的东西里面的选项根据Item的不同可以或多或少 比如说歌曲列表 有的只有下载和收藏 但有的还有mv等其他选项 昨天参考了gitHub上的一个例子 https
  • JVM GC

    文章目录 GC 核心概述 Java 自动化内存管理 什么是垃圾 内存碎片的概念 为什么需要 GC GC 相关算法对比 垃圾回收相关算法 标记阶段 引用计数算法 标记阶段 可达性分析算法 清除阶段 标记 清除 Mark Sweep 算法 清除
  • C++ 基类与派生类

    基类的私有成员在派生类中可以被继承 用sizeof也可以证明 但是不能直接访问 可以通过间接方式访问到 不能在派生类中用派生类函数调用访问 必须借助于继承的基类的公有成员函数访问基类的私有成员 C 为了确保程序员不会把系统内置类型的运算符进
  • 【Python练习:幸运7游戏】:使用随机数生成函数randrange()模仿筛子点数和判断概率问题,多次迭代求规律

    Python练习题 幸运7游戏 随机数的应用 题目 赌场中有一种称为 幸运7 的游戏 游戏规则是玩家掷两枚骰子 如果其点数和为7 玩家赢4元 如果不是7 玩家就输1元 请你分析一下 这样的规则是否公平 知识准备 这里用到一个python库自
  • mybatis连接mysql url_MyBatis与JDBC连接数据库所使用的url之间的差异

    在Windows7 系统上安装了MySQL 8 0 然后创建Maven工程 配置pom xml文件 添加了如下依赖 org mybatis mybatis 3 4 6 mysql mysql connector java 8 0 11 1
  • 如何保证某个函数只被调用一次

    From http www cnblogs com baiyanhuang archive 2010 11 13 1876677 html 一个函数caller会在其内部调用另外一个函数callee 现在的情况是 caller可能会在多个地
  • 智能指针原理剖析(一):auto_ptr、unique_ptr

    通过常规指针管理动态内存的难点及缺点 1 忘记释放动态内存 使用new malloc分配动态内存时 需要使用delete free手动释放内存 但程序员容易忘记释放内存 从而产生内存泄露 2 动态内存释放时机不对 在尚有指针引用内存的情况下