C++11智能指针(六):unique_ptr介绍与例子

2023-05-16

本节介绍下c++11提供的智能指针实现: std::unique_ptr<>

什么是std::unique_ptr

unique_ptr <>是c ++ 11提供的智能指针实现之一,用于防止内存泄漏。unique_ptr对象包含一个原始指针,并负责其生命周期。当这个对象被销毁的时候,它的析构函数会删除关联的原始指针。
unique_ptr有重载的- >和*运算符,所以它可以被用于类似于普通的指针。

示例:

#include <iostream>
#include <memory>

struct Task {
  int mId;
  Task(int id) : mId(id) {
    std::cout << "Task::Constructor" << std::endl;
  }
  ~Task() {
    std::cout << "Task::Destructor" << std::endl;
  }
};

int main() {
  //通过原始指针创建unique_ptr对象
  std::unique_ptr<Task> taskPtr(new Task(23));

  int id = taskPtr->mId;

  //通过unique_ptr访问元素
  std::cout << id << std::endl;

  return 0;
}
输出:
Task::Constructor
23
Task::Destructor
unique_ptr <Task>对象 taskPtr接受一个原始指针作为参数。当函数退出时,这个对象将超出范围,并且析构函数将被调用。在其析构函数中,unique_ptr对象taskPtr删除关联的原始指针。
所以,即使函数正常或异常退出(由于某些异常),taskPtr的析构函数将始终被调用。这样,原始指针总是会被删除,并防止内存泄漏。

唯一指针的唯一所有权

unique_ptr对象始终是关联的原始指针的唯一所有者。 我们不能复制一个unique_ptr对象,它只能移动。
由于每个unique_ptr对象是原始指针的唯一拥有者,因此在其析构函数中直接删除关联的指针。不需要任何参考计数,因此它非常轻量。

创建空的unique_ptr对象

//空unique_ptr对象
std::unique_ptr<int> ptr1;
ptr1没有与之关联的原始指针。 因此它是空的。

检查unique_ptr对象是否为空

有两种方法检查unique_ptr <>对象是否为空,或者是否有与之相关的原始指针:
方法1:

//检查unique_ptr对象是否为空
if(!ptr1)
	std::cout<<"ptr1 is empty"<<std::endl;
方法2:
//检查unique_ptr对象是否为空
if(ptr1 == nullptr)
	std::cout<<"ptr1 is empty"<<std::endl;


使用原始指针创建unique_ptr

要创建一个非空的unique_ptr <>对象,我们需要在构造函数中传递原始指针,同时创建对象。

//使用原始指针创建unique_ptr对象
std::unique_ptr<Task> taskPtr(new Task(23));
不能通过赋值创建unique_ptr<>对象,否则会导致编译错误
//std::unique_ptr<Task> taskPtr2 = new Task();   //编译错误


重置unique_ptr

调用unique_ptr<>对象上的reset()函数将重置该对象,即它将删除关联的原始指针并使unique_ptr<>对象为空:
//重置unique_ptr会删除关联的原始指针并使unique_ptr对象为空
taskPtr.reset();


unique_ptr对象不可复制

由于unique_ptr <>不可复制,只能移动。 因此,我们不能通过复制构造函数或赋值运算符来创建unique_ptr对象的副本。

//通过原始指针创建unique_ptr对象
std::unique_ptr<Task> taskPtr2(new Task(55));

//编译错误,unique_ptr对象不可复制
std::unique_ptr<Task> taskPtr3 = taskPtr2;

//编译错误,unique_ptr对象不可复制
taskPtr = taskPtr2;

复制构造函数和赋值运算符都在unique_ptr <>类中被删除。


转移unique_ptr对象的所有权

我们不能复制一个unique_ptr对象,但我们可以移动它们。这意味着一个unique_ptr对象可以将相关的原始指针的所有者转移到另一个unique_ptr对象。 让我们通过一个例子来理解:

创建一个unique_ptr对象
//通过原始指针创建unique_ptr对象
std::unique_ptr<Task> taskPtr2(new Task(55));
taskPtr2非空
现在将任务的关联指针的所有权转移给一个新的unique_ptr对象,即:
{
  //传递所有权
  std::unique_ptr<Task> taskPtr4 = std::move(taskPtr2);

  if(taskPtr2 == nullptr)
  std::cout<<"taskPtr2 is empty"<<std::endl;

  //所有权从taskPtr2传递给了taskPtr4
  if(taskPtr4 != nullptr)
  std::cout<<"taskPtr4 is not empty"<<std::endl;

  std::cout<<taskPtr4->mId<<std::endl;

  //taskPtr4超出了作用范围,删除相关原始指针
}
std :: move()把taskPtr2转换成一个RValue引用。所以unique_ptr的移动构造函数被调用,并且关联的原始指针可以被传送到taskPtr4。
将原始指针的所有权转移给taskPtr4后,taskPtr2将为空。

释放关联的原始指针

调用unique_ptr对象上的release()将释放对象的关联原始指针的所有权。

//通过原始指针创建unique_ptr对象
std::unique_ptr<Task> taskPtr5(new Task(55));

if(taskPtr5 != nullptr)
	std::cout<<"taskPtr5 is not empty"<<std::endl;
	
//释放来自原始指针的对象的所有权
Task * ptr = taskPtr5.release();

if(taskPtr5 == nullptr)
	std::cout<<"taskPtr5 is empty"<<std::endl;

完整的例子:

#include <iostream>
#include <memory>

struct Task {
  int mId;
  Task(int id) : mId(id) {
    std::cout << "Task::Constructor" << std::endl;
  }
  ~Task() {
    std::cout << "Task::Destructor" << std::endl;
  }
};

int main() {
  //空unique_ptr对象
  std::unique_ptr<int> ptr1;

  //检查unique_ptr对象是否为空
  if (!ptr1) {
    std::cout << "ptr1 is empty" << std::endl;
  }

  //检查unique_ptr对象是否为空
  if (ptr1 == nullptr) {
    std::cout << "ptr1 is empty" << std::endl;
  }

  //不能通过赋值初始化创建unique_ptr对象
  //std::unique_ptr<Task> taskPtr2 = new Task(); //编译错误

  //通过原始指针创建unique_ptr对象
  std::unique_ptr<Task> taskPtr(new Task(23));

  //检查taskPtr是否为空,或者是否有关联的原始指针
  if (taskPtr != nullptr) {
    std::cout << "taskPtr is  not empty" << std::endl;
  }

  //通过unique_ptr访问内部元素
  std::cout << taskPtr->mId << std::endl;

  std::cout << "Reset the taskPtr" << std::endl;
  //重置unique_ptr将删除关联的原始指针,并使unique_ptr对象为空
  taskPtr.reset();

  //检查taskPtr是否为空,或者是否有关联的原始指针
  if (taskPtr == nullptr) {
    std::cout << "taskPtr is  empty" << std::endl;
  }

  //通过原始指针创建unique_ptr对象
  std::unique_ptr<Task> taskPtr2(new Task(55));

  if (taskPtr2 != nullptr) {
    std::cout << "taskPtr2 is  not empty" << std::endl;
  }

  //unique_ptr 对象不可复制
  //taskPtr = taskPtr2;  //编译错误

  //unique_ptr 对象不可复制
  //std::unique_ptr<Task> taskPtr3 = taskPtr2; //编译错误

  {
    //转移所有权
    std::unique_ptr<Task> taskPtr4 = std::move(taskPtr2);

    if (taskPtr2 == nullptr) {
      std::cout << "taskPtr2 is  empty" << std::endl;
    }

    //taskPtr2的所有权转移给了task4
    if (taskPtr4 != nullptr) {
      std::cout << "taskPtr4 is not empty" << std::endl;
    }

    std::cout << taskPtr4->mId << std::endl;
    //taskPtr4超出范围并删除关联的原始指针
  }

  //通过原始指针创建unique_ptr对象
  std::unique_ptr<Task>taskPtr5(new Task(55));

  if (taskPtr5 != nullptr) {
    std::cout << "taskPtr5 is not empty" << std::endl;
  }

  //从原始指针释放对象的所有权
  Task* ptr = taskPtr5.release();

  if (taskPtr5 == nullptr) {
    std::cout << "taskPtr5 is empty" << std::endl;
  }

  std::cout << ptr->mId << std::endl;

  delete ptr;

  return 0;
}
输出:
ptr1 is empty
ptr1 is empty
Task::Constructor
taskPtr is  not empty
23
Reset the taskPtr
Task::Destructor
taskPtr is  empty
Task::Constructor
taskPtr2 is  not empty
taskPtr2 is  empty
taskPtr4 is not empty
55
Task::Destructor
Task::Constructor
taskPtr5 is not empty
taskPtr5 is empty
55
Task::Destructor


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

C++11智能指针(六):unique_ptr介绍与例子 的相关文章

  • R中按日期计算唯一值的数量

    请帮我计算每个日期的唯一 ID 的数量 所以 最初 有这个 ID 和日期的数据框 ID Date 1 2009 11 1 1 2009 11 2 1 2009 11 2 2 2009 11 1 2 2009 11 1 2 2009 11 2
  • yq (GO/Mike Farah) 递归地唯一化所有数组

    这可能与我发布的另一个问题有关 yq GO Mike Farah 对所有数组进行递归排序 https stackoverflow com questions 73746627 yq go mike farah sort all arrays
  • 如何根据 powershell 中对象的两个属性来选择唯一的对象?

    我有一个具有 6 个属性的对象数组 看起来像这样 csvData CURRENT DATE AND TIME 07 10 2015 08 17 17 CST USER NAME userName COMPUTER NAME computer
  • mysql唯一索引在java中用作异常处理方法

    我想知道在java中根据sql的唯一索引捕获异常是否是一个好主意 我想捕获像 1 0 的重复条目 这样的异常 如果是这样 则处理异常 否则正确插入数据库表中 我说你不要这样做 有两个原因 错误消息有点不清楚 错误 1062 23000 密钥
  • 查找数据库表的唯一约束

    我正在尝试使用 Java 查找表的唯一约束 在 Oracle 数据库上 但这应该没有区别 我找到了一种发现表主键的方法 这要归功于 DatabaseMetaData 的 getPrimaryKeys 然而 我无法找到表格的独特约束 互联网也
  • R:如何根据另一个变量中的值选择 dplyr::distinct() 保留哪一行?

    现实生活中的问题 我的受试者有 MRI 扫描数据 其中一些已被扫描多次 单独的行 其中一些每次都是根据不同的协议进行扫描的 我想按主题 ID 保留所有唯一行 如果主题是在两种不同的协议下扫描的 我希望它更喜欢其中一种 玩具示例 librar
  • swift hashable 协议哈希函数是否需要返回唯一值?

    我正在学习 iOS swift 俄罗斯方块教程 并已完成并运行 但我对一个特定的方面感到困惑 Hashable 协议 功能 class Block Hashable Printable var hashValue Int return se
  • split() 操作后获取 pandas 中唯一的字符串列表

    我正在开始使用熊猫 并且已经较大 DataFrame 中的一列数据例如 0 one two 1 two seven six 2 three one five 3 seven five five eight 4 six four 5 thre
  • 删除结构 C++ 向量中的重复项

    我有以下结构 我想将结构存储在向量中 其次我想删除 context 我究竟做错了什么 include
  • PostgreSQL 索引中的重复键

    我想将 OwnCloud 数据库移动到新服务器 但恢复期间操作失败 pg restore archive program db COPY failed for table oc storages ERROR value of a dupli
  • Pandas GroupBy - 仅显示具有多个唯一特征值的组

    我有一个数据框df things看起来像这样 我想在训练之前预测分类的质量 A B C CLASS al1 bal1 cal1 Ship al1 bal1 cal1 Ship al1 bal2 cal2 Ship al2 bal2 cal2
  • 两个字段的唯一约束及其相反

    我有一个数据结构 必须在其中存储元素对 每对恰好有 2 个值 因此我们使用一个表 其中包含字段 左值 右值 这些对应该是唯一的 如果密钥发生更改 它们将被视为相同 Example Fruit Apple is the same as App
  • PHP - 使关联数组唯一,键 -> 值和值 -> 键

    我在 php 中遇到了一个小问题 我发现很难用语言解释 我有一个包含键值的关联数组 我想创建一个函数 或者如果已经有一个函数 它将接受一个数组作为输入并删除重复项 但两种方式都是如此 例如 在我的数组中 我有 a gt b a gt c b
  • 仅从列表中检索非重复元素

    从 Python 列表中仅检索非重复元素的最佳选项是什么 假设我有以下列表 lst 1 2 3 2 3 4 我想检索以下内容 lst 1 4 2 and 3在该列表中不是唯一的 因此不会检索到它们 Use collections Count
  • python计算csv列中唯一元素的数量

    我正在尝试使用 Python 获取 csv 列中唯一项目的计数 示例 CSV 文件 没有标题 AB asd AB poi AB asd BG put BG asd 到目前为止我已经尝试过了 import csv from collectio
  • Javascript数组排序和唯一性

    我有一个像这样的 JavaScript 数组 var myData 237 124 255 124 366 255 我需要数组元素是唯一的并且已排序 myData 0 124 myData 1 237 myData 2 255 myData
  • R - 根据两列识别并删除重复行

    我有一些数据看起来像这样 Course ID Text ID 33 17 33 17 58 17 5 22 8 22 42 25 42 25 17 26 17 26 35 39 51 39 由于没有编程背景 我发现很难清楚地表达我的问题 但
  • SQL聚合函数选择唯一值

    我有一个包含两列的行集 technical id and natural id 行集实际上是复杂查询的结果 假设列值之间的映射是双射的 即对于具有相同值的两行 technical id the natural ids 也相同 对于不同的te
  • 如何使 cassandra 中的值独一无二

    我想在 cassandra 中进行唯一约束 因为我希望我的专栏中的所有值在我的专栏系列中都是唯一的 前任 名字 拉胡尔 电话123 地址 abc 现在我希望我这一行没有等于 rahul 123 和 abc 的值在 datastax 上搜索时
  • 如何从数组C++中获取唯一的字符串

    我知道我的问题对某些人来说可能很愚蠢 但我整天用谷歌搜索并尝试制定自己的解决方案 但我失败了 请帮助 我需要从简单的字符串数组中打印所有唯一的字符串 example 输入 嗨 我的 名字 嗨 土豆 文本 名字 嗨 输出 我的 土豆 文本 我

随机推荐

  • TCP/UDP调试工具的使用

    TCP UDP调试工具下载链接 前文 当我们写好一个TCP UDP的程序时 但是无法通信时 光看代码又找不出原因时 我们可以借助调试工具来检查是服务端还是客户端出现了问题 这样就很大的减少了错误的排查范围 再次感叹一下 这个工具真的很好用
  • 关于利用结构体和联合体数据收发的两种方法

    关于利用结构体和联合体数据收发的两种方法 关于最近接手的小项目 xff0c 有了一些经验 xff0c 所以进行一下记录 文章目录 关于利用结构体和联合体数据收发的两种方法前言一 联合体法二 结构体法小tips 前言 在我们利用自己的板子进行
  • RESTful初探之四(Restlets)

    size 61 large Restlets Restlet项目为 建立REST概念与Java类之间的映射 提供了一个轻量级而全面的框架 它可用于实现任何种类的REST式系统 xff0c 而不仅仅是REST式Web服务 color 61 r
  • FreeRTOS中的堆栈设置”与“系统启动文件中堆栈”的关系

    FreeRTOS中的堆栈设置 与 系统启动文件中堆栈 的关系 在STM32CubeMX生成工程时发现 xff0c 在FreeRTOS的配置中同样有TOTAL HEAP SIZE堆的大小配置 xff0c 这个堆与之前系统的堆空间有什么区别呢
  • nodejs 实现http账号密码Digest登录认证

    const http 61 require 39 http 39 const qs 61 require 39 querystring 39 const md5 61 require 39 md5 node 39 第一步 xff1a 获取n
  • PCB Layout各层含义与分层原则

    内容包括 PCB绘图软件各层含义的详细介绍以及一些在实际工作中的应用 xff0c Layout时多层板分层原则与阻抗匹配 紫色文字是超链接 xff0c 点击自动跳转至相关博文 持续更新 xff0c 原创不易 xff01 目录 xff1a 一
  • 2021-01-18

    求助 xff0c 关于Ubuntu20 04安装网络调试助手打不开的问题 我在虚拟机上安装了Ubuntu20 04并安装了网络调试助手 xff0c 但却打不开 xff0c 运用了sudo apt get libqtgui4 amd64也没用
  • 笔记:VSCode C/C++ 格式化修改设置

    VSCode安装C C 43 43 插件后 xff0c 就有了格式化代码的能力 xff0c 这个功能很好用 xff0c 一般来说不用改就可以用的很嗨皮 为啥要改默认设置 xff0c 只因不喜欢函数内大括号独占一行 xff0c 如此一屏显示的
  • NEMA 协议:GPRMC数据格式

    NEMA协议的由来 NMEA协议是为了在不同的GPS xff08 全球定位系统 xff09 导航设备中建立统一的BTCM xff08 海事无线电技术委员会 xff09 标准 xff0c 由美国国家海洋电子协会 xff08 NMEA The
  • 大小端(网络字节序)等概念

    1 大小端定义 大端存储模式 xff1a 是指数据的低位字节序保存在内存的高地址中 xff0c 而数据的高位字节序保存在内存的低地址中 小端存储模式 xff1a 是指数据的低位字节序保存在内存的低地址中 xff0c 而数据的高位字节序保存在
  • [李景山php]RHEL\CentOS 7\ubuntu16.04 下 MySQL 连接数被限制为214个

    问题 项目中 xff0c 由于连接数过多 xff0c 提示 Too many connections xff0c 需要增加连接数 我在 etc my cnf中修改了 max connections 61 2000 但是 xff0c 实际连接
  • 关系型数据库和非关系型数据库的特性以及各自的优缺点

    数据库 类型特性优点缺点关系型数据库 SQLite Oracle mysql1 关系型数据库 xff0c 是指采用了关系模型来组织 数据的数据库 xff1b 2 关系型数据库的最大特点就是事务的一致性 xff1b 3 简单来说 xff0c
  • 采用libuv的epoll方式实现的异步高性能libcurl发送数据的方法

    Libcurl较为基本的用法是easyinterface xff0c 它是最简单的同步接口 xff0c 容易理解 xff0c 实现代码简单 xff0c 但是性能低下 curl multi perform 43 select xff1a 可以
  • 各种浏览器语言包、国际化如何配置

    size 61 large 如果web项目使用了国际化多语言包 xff0c 切换浏览器语言包可以切换语言 xff1a color 61 red Firefox如何中英文切换 color 首先得下载语言包 xff0c 网址 xff1a url
  • libcurl采用curl_multi_perform() + curl_multi_wait()方式实现异步高性能l发送数据的方法

    前两篇文章 c c 43 43 调用libcurl库发送http请求的两种基本用法 采用libuv的epoll方式实现的异步高性能libcurl发送数据的方法 讲述了采用libcurl发送数据的基础方法和高性能方法 xff0c 基础方法较为
  • 网络库libevent、libev、libuv对比

    Libevent libev libuv 三个网络库 xff0c 都是c 语言实现的异步事件库Asynchronousevent library xff09 异步事件库本质上是提供异步事件通知 xff08 Asynchronous Even
  • 记flume部署过程中遇到的问题以及解决方法(持续更新)

    项目需求是将线上服务器生成的日志信息实时导入kafka xff0c 采用agent和collector分层传输 xff0c app的数据通过thrift传给agent xff0c agent通过avro sink将数据发给collector
  • c++11多线程编程(一):创建线程的三种方法

    c 43 43 11线程库 原始的c 43 43 标准仅支持单线程编程 xff0c 新的c 43 43 标准 xff08 c 43 43 11或c 43 43 0x xff09 于2011年发布 xff0c 引入了新的线程库 编译器要求 L
  • c++11多线程编程(六):事件处理

    本节讨论在多线程环境下的事件处理 有时 xff0c 线程需要等待某事件发生 xff0c 比如一个条件变为true xff0c 或者某任务被另一个线程完成 例如 xff0c 我们创建一个基于网络的应用程序 xff0c 处理如下的任务 xff1
  • C++11智能指针(六):unique_ptr介绍与例子

    本节介绍下c 43 43 11提供的智能指针实现 std unique ptr lt gt 什么是std unique ptrunique ptr lt gt 是c 43 43 11提供的智能指针实现之一 xff0c 用于防止内存泄漏 un