c++智能指针(一)

2023-11-13

C++智能指针(一)

 c++中的动态内存的管理是通过一对运算符来管理的:new ,在动态内存中为对象分 配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化,delete,接受一个对象的指针,销毁对象,并且释放与之关联的内存。
 动态内存的使用很容易造成问题,因为确保在正确的时间释放内存是特别困难的。如果我们初始化指针后未调用delete释放分配的内存,就会造成内存泄露,解决这个问题最有效的方法是使用智能指针(smart pointer)。智能指针是存储指向动态分配(堆)对象指针的类,用于生存期的控制,能够确保在离开指针所在作用域时,自动地销毁动态分配的对象,防止内存泄露。智能指针的核心实现技术是引用计数,每使用它一次,内部引用计数加1,每析构一次内部的引用计数减1,减为0时,删除所指向的堆内存。
 c++新的标准库提供了两种智能指针类型来动态管理对象。智能指针的行为类似于常规指针,重要的区别就是在于底层管理指针的方式:shared_ptr允许多个指针指向同一个对象。unique_ptr则“独占”所指向的对象。标准库还定义了一个名为weak_ptr的伴随类,是一种弱引用,指向shared_ptr所管理的对象。这三种类型的定义都在头文件memory中。

shared_ptr

  和vector类似,智能指针也是模板,因此我们在创建智能指针时必须指明指针可以指向的类型。同vector一样我们在尖括号内给出类型,之后是所定义的智能指针的名字。

    //shared_ptr 可以指向int
	std::shared_ptr<int> p1;
	//shared_ptr 可以指向string
	std::shared_ptr<std::string> p2;
初始化

 智能指针的使用方法和普通指针类似,解引用一个智能指针返回它指向的对象。默认初始化的智能指针包含一个空指针,如果在条件判断中使用智能指针,其作用就是检查它是否为空。

//如果p2不为空。检查其是否指向一个空string
	if (p2 && p2->empty())
	{
		*p2 = "Hi";
	}

 最安全的分配和使用动态内存的方法是调用标准库中的一个名为make_shared的函数,此函数在动态内存中分配一个对象并初始化它

// 1 通过构造函数、std::shared_ptr辅助函数、reset方法来初始化
	std::shared_ptr<int> p3(new int(1));
	//error 缺少类模板的参数列表
	//std::shared_ptr p4 = p3;
	std::shared_ptr<int> p4 = p3;
	std::shared_ptr<int> p5;
	// 与赋值类似,reset会更新引用计数,p5指向一个新对象,p5原来指向的对象计数-1
	p5.reset(new int(1)); 
	if (p5) {
		std::cout << "p5 not null" << std::endl;
	}

	//应该优先使用make_shared来构造智能指针,更高效
	auto p1 = std::make_shared<int>(100);
	// 相当于
	std::shared_ptr<int> sp1(new int(100));
拷贝、赋值

 进行拷贝或者赋值操作时,每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象;我们可以理解为每个shared_ptr都有一个关联的计数器,通常称为引用计数,无论何时我们拷贝一个shared_ptr时,计数器都会递增。当我们给shared_ptr赋予一个新值或是shared_ptr被销毁时计数器就会递减,当一个shared_ptr的计数器变为0时会自动释放自己所管理的对象。

std::shared_ptr<int> sp1(new int(100));
	std::shared_ptr<int> p = sp1; 

在这里插入图片描述

常用函数

share_ptr 和 unique都支持的操作:

*p 解引用p,获得它指向的对象
p->mem 等价于*p->mem
p.get() 返回p中保存的指针。要小心使用,若智能指针释放了对象,返回的指针所指向的对象也消失了
swap(p,q)/p.swap(q) 交换p,q中的指针

share_ptr独有的操作:

make_shared(args) 返回一个shared_ptr,指向一个动态分配类型为T的对象,使用args初始化此对象
shared_ptrp(q) p是shared_ptr q的拷贝,此操作会递增q中的计数器
p = q p和q都是shared_ptr,所保存的指针类型必须能互相转换,此操作会递减p的引用计数,递增q的引用计数,如果p的引用计数变为0,则会将其管理的原内存释放
p.unique() 如果p的use_count为1返回true,否则返回false
p.use_count() 返回与p共享的智能指针数量

unique_ptr

 一个unique_ptr拥有它所指向的对象,和shared_ptr不同,某个时刻智只能有一个unique_ptr指向一个定对象,当unique_ptr被销毁时其指向的对象也会被一同销毁。

初始化

 和shared_ptr不同,没有类似于make_shared的标准库函数返回一个unique_ptr。必须采用直接初始化的形式。

	std::unique_ptr<std::string> p1;
	std::unique_ptr<std::string> p2(new std::string("Hi"));
拷贝、赋值

  因为unique_ptr拥有其指向的对象,因此unique_ptr不支持普通的拷贝或者赋值操作。

	//error
	p1 = p2;
	//error
	std::unique_ptr<std::string> p3(p2);

虽然不能通过拷贝或者赋值一个unique_ptr,但是可以通过调用release或reset将指针的所有权从一个(非const)unique_ptr转移给另一个unique;

std::unique_ptr<std::string> p1(new std::string("Hi"));
	//release成员返回unique当前保存的指针并将其置为空
	//将p1指向对象的所有权转移给p2,release将p1置为空
	std::unique_ptr<std::string> p2(p1.release());
	std::unique_ptr<std::string> p3(new std::string("No!"));
	//所有权从p3转移给p2,reset释放了p2原本指向的内存
	p2.reset(p3.release());
	/*
		release会切断unique_ptr和它原本管理的对象之间的联系,release返回的指针一般被用来初始化另一个智能指针或者给另
	一个智能指针赋值,如果不用另一个智能指针来保存release返回的指针,我们必须手动释放资源,
	*/
	//error,p2不会释放内存,并且我们丢失了指针
	p2.release();
	//yes,但是记得delete(p)
	auto p = p2.release();
常用函数
unique_ptr u1、unique_ptr<T,D> u2 空unique_ptr,可以指向内心为T的对象,u1会使用delete来释放他的指针;u2会使用一个类型为D的可调用对象来释放它的指针
unique_ptr<T,D> u(d) 空 unique_ptr,指向类型为T的对象,用类型为D的对象代替delete
u = nullptr 释放u指向的对象,将u置为空
u.release() u放弃对指针的控制权,返回指针并将u置为空
u.reset() 释放u指向的对象
u.reset(q)、u.reset(nullptr) 如果提供了内置指针q,则u指向这个对象,否则将u置为空

weak_ptr

 weak_ptr是一种不控制对象生存期的智能指针,它指向一个由shared_ptr管理的对象,将weak_ptr绑定到一个由shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放,weak_ptr即使指向该对象,这个对象也会被释放(弱引用)。

初始化

创建一个weak_ptr时要用一个shared_ptr来初始化它。

	auto p7 = std::make_shared<int>(100);
	//p弱共享p7,p7的引用计数不改变
	std::weak_ptr<int> p(p7);

在这里插入图片描述
由于对象有可能不存在,因此不能使用weak_ptr直接访问对象,而必须调用lock,此函数会检查weak_ptr指向的对象是否存在,如果存在,lock会返回一个指向共享对象的shared_ptr。

	if (p7 == p.lock())
	{
		//在这个if里面 p7和p共享对象
	}
常用操作
weak_ptrw 空weak_ptr可以指向类型为T的对象
weak_ptr w(sp) 与shared_ptr sp指向相同对象的weak_ptr
w = p p可以是weak_ptr,也可以是weak_ptr,赋值后w与p共享对象
w.reset() 将w置为空
w.use_count() 与w共享对象的shared_ptr的数量
w.expired() 如果w.use_count()为0返回true,否则返回false
w.lock() 如果expired为true,返回一个空shared_ptr,否则返回一个指向w的对象的shared_ptr

参考书籍 :
《C++ Primer 第五版》

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

c++智能指针(一) 的相关文章

  • 起订量要求?违背了目的?

    是否需要虚拟化您想要模拟的所有属性访问器就违背了模拟的目的 我的意思是 如果我必须修改我的对象并虚拟化我想要模拟的每个访问器 我难道不能继承我的类并自己模拟它吗 你的问题非常有效 但如果你仔细想想 没有其他方法可以模拟课程 如果你采用一个接
  • Accept() 是线程安全的吗?

    我目前正在用 C 语言为我正在做的课程编写一个简单的网络服务器 我们的一项要求是实现一个线程池来使用 pthread 处理连接 我知道我将如何粗略地执行此操作 在主线程中调用accept并将文件描述符传递给freee线程 但是我的朋友建议了
  • 如何从RichTextBox中获取显示的文本?

    如何获得显示的RichTextBox 中的文本 我的意思是 如果 RichTextBox 滚动到末尾 我只想接收那些对我来说可见的行 P S 获得第一个显示的字符串就足够了 您想使用 RichTextBox GetCharIndexFrom
  • 在Application_AquireRequestState事件中用POST数据重写Url

    我有一个在其中注册路线的代码Application AcquireRequestState应用程序的事件 注册路由后 我会在 Http 运行时缓存中设置一个标志 这样我就不会再次执行路由注册代码 在此事件中注册路线有特定原因Applicat
  • 用户控件内所有控件均为空

    我有一个 UserControl 它使用 UserControl 以及其他控件 In the ascx文件我有以下代码
  • 访问“if”语句之外的变量

    我怎样才能使insuranceCost以外可用if陈述 if this comboBox5 Text Third Party Fire and Theft double insuranceCost 1 在 if 语句之外定义它 double
  • 如何在不实例化一个类的情况下检查它是否继承了另一个类? [复制]

    这个问题在这里已经有答案了 假设我有一个如下所示的类 class Derived some inheritance stuff here 我想在我的代码中检查类似的内容 Derived is SomeType 但看起来像is运算符需要 De
  • 无法从 Web api POST 读取正文数据

    我正在尝试从新的 Asp Net Web Api 中的请求中提取一些数据 我有一个像这样的处理程序设置 public class MyTestHandler DelegatingHandler protected override Syst
  • 如何在编译C代码时禁用警告?

    我正在使用 32 位 Fedora 14 系统 我正在使用编译我的源代码gcc 有谁知道如何在编译c代码时禁用警告 EDIT 是的 我知道 最好的办法是修复这些警告以避免任何未定义 未知的行为 但目前在这里 我第一次编写了巨大的代码 并且在
  • 如何在 Asp.net Gridview 列中添加复选框单击事件

    我在 asp 中有一个 gridview 其中我添加了第一列作为复选框列 现在我想选择此列并获取该行的 id 值 但我不知道该怎么做 这是我的 Aspx 代码
  • 方法“xxx”不能是事件的方法,因为该类派生的类已经定义了该方法

    我有一个代码 public class Layout UserControl protected void DisplayX DisplayClicked object sender DisplayEventArgs e CurrentDi
  • C# datagridview 列转入数组

    我正在用 C 构建一个程序 并在其中包含一个 datagridview 组件 datagridview 有固定数量的列 2 我想将其保存到两个单独的数组中 但行数确实发生了变化 我怎么能这样做呢 假设一个名为 dataGridView1 的
  • 操纵 setter 以避免 null

    通常我们有 public string code get set 如果最终有人将代码设置为 null 我需要避免空引用异常 我尝试这个想法 有什么帮助吗 public string code get set if code null cod
  • 无法加载文件或程序集“EntityFramework,版本=6.0.0.0”

    我究竟做错了什么 我该如何解决这个问题 我有一个包含多个项目的解决方案 它是一个 MVC NET 4 5 Web 应用程序 在调试模式下启动后调用其中一个项目时 出现此错误 导致此错误的项目具有以下参考 两个都是版本6 0 0 0 应用程序
  • 在简单注入器中注册具有多个构造函数和字符串依赖项的类型

    我正在尝试弄清楚如何使用 Simple Injector 我在项目中使用了它 注册简单服务及其组件没有任何问题 但是 当组件具有两个以上实现接口的构造函数时 我想使用依赖注入器 public DAL IDAL private Logger
  • 如何用 C 语言练习 Unix 编程?

    经过五年的专业 Java 以及较小程度上的 Python 编程并慢慢感觉到我的计算机科学教育逐渐消失 我决定要拓宽我的视野 对世界的一般用处 并做一些 对我来说 感觉更重要的事情就像我真的对机器有影响一样 我选择学习 C 和 Unix 编程
  • 允许使用什么类型的内容作为 C 预处理器宏的参数?

    老实说 我很了解 C 编程语言的语法 但对 C 预处理器的语法几乎一无所知 尽管我有时在编程实践中使用它 所以问题来了 假设我们有一个简单的宏 它扩展为空 define macro param 可以放入宏调用构造中的语法有哪些限制 调用宏时
  • 将非算术类型作为参数传递给 cmath 函数是否有效?

    给定以下用户定义类型S具有转换功能double struct S operator double return 1 0 以及以下调用cmath http en cppreference com w cpp header cmath使用类型的
  • 纯虚函数可能没有内联定义。为什么?

    纯虚函数是那些虚函数并且具有纯说明符 0 第 10 4 条第 2 款C 03 的内容告诉我们什么是抽象类 顺便说一句 如下 注意 函数声明不能 同时提供纯说明符和定义 尾注 示例 struct C virtual void f 0 ill
  • 如何设置 CMake 与 clang 交叉编译 Windows 上的 ARM 嵌入式系统?

    我正在尝试生成 Ninja makefile 以使用 Clang 为 ARM Cortex A5 CPU 交叉编译 C 项目 我为 CMake 创建了一个工具链文件 但似乎存在错误或缺少一些我无法找到的东西 当使用下面的工具链文件调用 CM

随机推荐

  • R语言-ggplot2图形语法

    简介 在R里 主要有两大底层图层系统 一是base图形系统 二是gird图形系统 lattice包与ggplot2包正是基于gird图形系统构建的 他们都有自己独特的图形语法 ggplot2有着自己独特的图形语法 这套语法归纳起来包括 数据
  • 魅族满载诚意强势回归,重启全胜时代?

    3月30日魅族在上海梅赛德斯 奔驰文化中心举办了史上最大规模的新品发布会 吸引了众多媒体 行业人士和魅友的关注 在发布会上 魅族正式推出了魅族20系列旗舰手机 以及Flyme 10系统 Flyme Auto车机系统等全场景融合体验产品 全方
  • JS 随机生成十个带颜色的li

    html和css部分
  • 量化投资学习-37:底部涨停板操作

    涨停板选股 1 异动 主力的拉升前的筹码集中度和压力试盘 金针探底 拉升回落 2 时间 10 00之前涨停最佳 10 30之前凑合 下午不可 3 空间 底部第一个涨停 后续还有较大的涨幅空间 4 缺口 通过缺口 快速脱离主力的成本区和价格底
  • java注解开发

    用xml配置文件方式是Servlet2 5版本规范的 经过逐步演变注解来时流行 因为更方便了 Servlet3 0以后也支持注解开发了 自动注解实现步骤 创建JavaWeb工程 并移除web xml 编写Servlet 继承HttpServ
  • react学习笔记-从井字棋开始(3)

    函数函组件 如果你想写的组件只包含一个 render 方法 并且不包含 state 那么使用函数组件就会更简单 我们不需要定义一个继承于 React Component 的类 我们可以定义一个函数 这个函数接收 props 作为参数 然后返
  • 120种小狗图像傻傻分不清?用fastai训练一个分类器

    作者 一杯奶茶的功夫 链接 https www jianshu com p ab35ed21df87 程序员转行学什么语言 https edu csdn net topic ai30 utm source csdn bw 这篇文章会讲解如何
  • windows xp 驱动开发(四) USB开发技术概述

    转载请标明是引用于 http blog csdn net chenyujing1234 欢迎大家提出意见 一起讨论 参考文章 http blog csdn net xxxluozhen article details 4882121 1 概
  • 远程桌面协议(RDP)介绍

    远程桌面协议 RDP 允许您远程访问计算机 多年来 它免除了许多系统管理操作 无疑是一项非常有用的技术 RDP 长期以来一直提供远程访问支持 而且越来越好 该协议于 1998 年在 Windows NT 4 0 Terminal Serve
  • Linux系统简介

    文章目录 1 UNIX与Linux发展史 1 1 UNIX发展史 1 2 Linux发展史 1 2 1 Linux内核版本 1 2 2 Linux主要发行版本 2 开源软件简介 2 1 典型的开源软件 2 2 开源软件的特点 2 3 支撑互
  • MATLAB实现多分类预测结果混淆矩阵(Confusion matrix)可视化

    对于多分类问题 如何对预测结果进行可视化分析是性能对比的关键 在实际多分类问题 除了简单展示模型预测精度外 如何理解不同类别之间的预测结果对于分析样本相关性和属性区别具有重要意义 在MATLAB中一般通过混淆矩阵confusion matr
  • Uber和它的规则&算法

    私以为 Uber这家公司的出现 标志着 科技重构资源的时代正式来临 这才是大数据真正的使命啊 enjoy 这个改变 以下信息来源 网络上流传的中文Uber解读 Uber的算法 均可以随着数据量的不断增加进行学习 所以只会越来越准 只会越来越
  • MySQL将一张表的数据copy到另一张表中

    1 复制旧表的数据到新表 假设两个表结构一样 INSERT INTO 新表 SELECT FROM 旧表 INSERT INTO tbl user copy SELECT FROM tbl user 2 复制表结构及数据到新表 CREATE
  • Keil不能正确生成.bin文件的解决办法

    1 打开keil IDE 然后打开help gt uVison Help 搜索fromelf关键字如下图1 然后再进入到右下角的索引找到fromelf命令行的语法和选项 找到 bin的说明如下 如红色标注所说 正是症结所在 即如果链接文件中
  • 安装ubuntu20.04(安装vim、gcc、VMtools、中文输入法、汉化、修改IP、无法连网问题)

    目录 ubuntu安装包获取 ubuntu的安装 安装网络配置命令ifconfig 连接网络 解决ubuntu无法连网问题 如何修改IP地址 安装VMtools 解决VMware Tools选项灰色 VMtools安装 安装中文 汉化 添加
  • 时间序列预测——GRU

    本文展示了使用GRU进行时间序列预测的全过程 包含详细的注释 整个过程主要包括 数据导入 数据清洗 结构转化 建立GRU模型 训练模型 包括动态调整学习率和earlystopping的设置 预测 结果展示 误差评估等完整的时间序列预测流程
  • 针对序列级和词元级应用微调BERT(需修改)

    对于序列级和词元级自然语言处理应用 BERT只需要最小的架构改变 额外的全连接层 如单个文本分类 例如 情感分析和测试语言可接受性 文本对分类或回归 例如 自然语言推断和语义文本相似性 文本标记 例如 词性标记 和问答 在下游应用的监督学习
  • 7-22龟兔赛跑/PTA基础编程题目集

    7 22 龟兔赛跑 20分 乌龟与兔子进行赛跑 跑场是一个矩型跑道 跑道边可以随地进行休息 乌龟每分钟可以前进3米 兔子每分钟前进9米 兔子嫌乌龟跑得慢 觉得肯定能跑赢乌龟 于是 每跑10分钟回头看一下乌龟 若发现自己超过乌龟 就在路边休息
  • 高效的学习方法

    背景 自己在复习自己专业课33页知识点时一筹莫展 死记硬背又记不住 背了上一个再背下一个上一个就忘记了 在复习的时候特别痛苦 而且定义性质的还是不能有错别字的 所以感觉自己背的特别痛苦 而且背完就忘 就像在做无用功 自己也想过用思维导图三遍
  • c++智能指针(一)

    C 智能指针 一 c 中的动态内存的管理是通过一对运算符来管理的 new 在动态内存中为对象分 配空间并返回一个指向该对象的指针 我们可以选择对对象进行初始化 delete 接受一个对象的指针 销毁对象 并且释放与之关联的内存 动态内存的使