unique_ptr

unique_ptr使用

1.介绍

unique_ptr是独占型智能指针,不允许其他指针共享内部指针,不允许赋值

unique_ptr<T> myptr(new T);
unique_ptr<T> myOther = myptr; // 错误不能复制

unique_ptr 可以通过函数返回给其他的unique_ptr,还可以通过std::move来转移unique_ptr,这样它本身不再拥有原来指针的所有权。

unique_ptr<T> myptr(new T);
unique_ptr<T> myOther = std::move(myptr); // ok
unique_ptr<T> ptr = myptr; // 错误不能转移,不能复制

unique_ptr 没有make_unique函数在C++11中,在C++14中支持,如下实现make_unique方法:

//make_unique的实现
//支持普通指针
template<class T, class... Args> inline
typename enable_if<!is_array<T>::value, unique_ptr<T> >::type make_unique(Args&&... args)
{return unique_ptr<T>(new T(std::forward<Args>(args)...));
}//支持动态数组
template<class T> inline
typename enable_if<is_array<T>::value && extent<T>::value==0, unique_ptr<T> >::type make_unique(size_t size)
{typedef typename remove_extent<T>::type U;return unique_ptr<T>(new U[size]());
}//过滤掉定长数组的情况
template<class T, class... Args>
typename enable_if<extent<T>::value != 0, void>::type make_unique(Args&&...) = delete;

如果不是数组,直接创建unique_ptr。如果是数组,先派单是否是定长数组,如果是定长数组编译不通过,如果是非定长数组,则获取数组中的元素类型,根据size创建动态数组。

==unique_ptr和shared_ptr相比除了独占特性,还可以指向一个数组。==如下代码:

std::unique_ptr<int []> ptr(new int[10]);
ptr[9] = 9; // 设置最后一个元素值为9
std::shared_ptr<int []> ptr(new int[10]); // 代码不合法

2.指定删除器

与shared_ptr相比,unique_ptr指定删除器的时候需要确定删除器类型,所以不能像shared_ptr那样直接指定删除器。

std::shared_ptr<int> ptr(new int(1),[](int* p){ delete p;}); // 正确
std::unique_ptr<int> ptr1(new int(1),[](int* p){ delete p;}); // 错误
std::unique_ptr<int,void(*)(int*)> ptr(new int(1),[](int* p){ delete p;}); // lamda在没有捕获变量时正确,如果捕获了变量就会编译报错

上述代码原因是在没有捕获变量时可以直接转化为函数指针,一旦捕获了就无法转换成函数指针了。

如果希望unique_ptr的删除器支持lamda,可以写成:

std::unique_ptr<int, std::function<void(int*)>> ptr(new int(1),[&](int* p){delete p;});

也可以自定义删除器

struct MyDelete
{void operator(int* p){delete p;}
};
int main()
{std::unique_ptr<int,MyDelete> p(new int(1));return 0;
}

3.使用场景

如果只希望一个智能指针管理资源或者管理数组使用unique_ptr,如果希望多个指针管理一个资源使用shared_ptr。

4.effective 介绍

class Investment { // 投资
public:virtual ~Investment() {}
};
class Stock : public Investment {}; // 股票
class Bond : public Investment {}; // 债券
class RealEstate : public Investment {}; // 不动产void makeLogEntry(Investment*) {}auto delInvmt1 = [](Investment* pInvestment) { // custom deleter(a lambda expression), 使用无状态lambda表达式作为自定义析构器makeLogEntry(pInvestment);delete pInvestment;};void delInvmt2(Investment* pInvestment) // 使用函数作为自定义析构器
{makeLogEntry(pInvestment);delete pInvestment;
}template<typename... Ts>
//std::unique_ptr<Investment> makeInvestment(Ts&&... params) // return std::unique_ptr to an object created from the given args
std::unique_ptr<Investment, decltype(delInvmt1)> makeInvestment(Ts&&... params) // 改进的返回类型,返回值尺寸与Investment*相同
//std::unique_ptr<Investment, void(*)(Investment*)> makeInvestment(Ts&&... params) // 返回值尺寸等于Investment*的尺寸+至少函数指针的尺寸
{//std::unique_ptr<Investment> pInv(nullptr);std::unique_ptr<Investment, decltype(delInvmt1)> pInv(nullptr, delInvmt1); // ptr to be returnedif (nullptr/* a Stoc object should be created*/) {pInv.reset(new Stock(std::forward<Ts>(params)...));} else if (nullptr/*a Bond object should be created*/) {pInv.reset(new Bond(std::forward<Ts>(params)...));} else if (nullptr/*a RealEstate object should be created*/) {pInv.reset(new RealEstate(std::forward<Ts>(params)...));}return pInv;
}int test_item_18()
{auto pInvestment = makeInvestment(/*arguments*/); // pInvestment is of type std::unique_ptr<Investment>std::shared_ptr<Investment> sp = makeInvestment(/*arguments*/); // converts std::unique_ptr to std::shared_ptrreturn 0;
} // destroy *pInvestment

C++11中共有四种智能指针:std::auto_ptr、std::unique_ptr、std::shared_ptr和std::weak_ptr。所有这些智能指针都是为管理动态分配对象的生命期而设计的,换言之,通过保证这样的对象在适当的时机以适当的方式析构(包括发生异常的场合),来防止资源泄漏。

std::auto_ptr是个从C++98中残留下来的弃用特性,它是一种对智能指针进行标准化的尝试,这种尝试后来成为了C++11中的std::unique_ptr。

std::unique_ptr可以做std::auto_ptr能够做的任何事,并且不止于此。它执行的效率和std::auto_ptr一样高,而且不用扭曲其要表达的本意去复制任何对象。它从任何方面来看都要比std::auto_ptr更好。

每当你需要使用智能指针时,std::unique_ptr基本上应是手头首选。可以认为在默认情况下(使用默认析构器)std::unique_ptr和裸指针(raw pointer)有着相同的尺寸,并且对于大多数的操作(包括提领(including dereferenceing)),它们都是精确地执行了相同的指令。

std::unique_ptr实现的是专属所有权(exclusive ownership)语义。一个非空的std::unique_ptr总是拥有其所指涉到的资源。移动一个std::unique_ptr会将所有权从源指针移至目标指针(源指针被置空)。std::unique_ptr不允许复制(copy),因为如果复制了一个std::unique_ptr,就会得到两个指涉到同一资源的std::unique_ptr,而这两者都认为自己拥有(因此应当析构)该资源。因而std::unique_ptr是个只移型别(move-only type)。在执行析构操作时,由非空的std::unique_ptr析构其资源。默认地,资源的析构是通过对std::unique_ptr内部的裸指针实施delete完成的。

std::unique_ptr的一个常见用法是在对象继承谱系中作为工厂函数的返回型别。

默认地,析构通过delete运算符实现,但是在析构过程中std::unique_ptr可以被设置为使用自定义析构器(custom delete):析构资源所调用的任意函数(或函数对象,包括那些由lambda表达式产生的)。

std::unique_ptr以两种形式提供,一种是单个对象(std::unique_ptr),另一种是数组(std::unique_ptr<T[]>)。单个对象形式不提供索引运算符(operator[]),而数组形式则不提供提领运算符(lack dereferencing operator)(operator*和operator->)。

std::unique_ptr是C++11中表达专属所有权的方式,但它还有一个十分吸引人的特性,就是std::unique_ptr可以方便高效地转换成std::shared_ptr。

要点速记:

(1).std::unique_ptr是小巧、高速的、具备只移型别的智能指针,对托管资源实施专属所有权语义。

(2).默认地,资源析构采用delete运算符来实现,但可以指定自定义删除器。有状态的删除器和采用函数指针实现的删除器会增加std::unique_ptr型别的对象尺寸。

(3).将std::unique_ptr转换成std::shared_ptr是容易实现的。

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

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

相关文章

深入解析 MySQL 启动方式:`systemctl` 与 `mysqld` 的对比与应用

目录 前言1. 使用 systemctl 启动 MySQL1.1 什么是 systemctl1.2 systemctl 启动 MySQL 的方法1.3 应用场景1.4 优缺点优点缺点 2. 使用 mysqld 命令直接启动 MySQL2.1 什么是 mysqld2.2 mysqld 启动 MySQL 的方法2.3 应用场景2.4 优缺点优点缺点 3. 对比分析结语 前言 MySQL …

会议直击|美格智能亮相2024紫光展锐全球合作伙伴大会,融合5G+AI共拓全球市场

11月26日&#xff0c;2024紫光展锐全球合作伙伴大会在上海举办&#xff0c;作为紫光展锐年度盛会&#xff0c;吸引来自全球的众多合作伙伴和行业专家、学者共同参与。美格智能与紫光展锐竭诚合作多年&#xff0c;共同面向5G、AI和卫星通信为代表的前沿科技&#xff0c;聚焦技术…

本地学习axios源码-如何在本地打印axios里面的信息

1. 下载axios到本地 git clone https://github.com/axios/axios.git 2. 下载react项目, 用vite按照提示命令配置一下vite react ts项目 npm create vite my-vue-app --template react 3. 下载koa, 搭建一个axios请求地址的服务端 a.初始化package.json mkdir koa-server…

7、递归

一、概念/理解 递归&#xff1a;某个函数直接或者间接的调用自身。--->函数调用 函数调用&#xff1a;创建副本 递归函数&#xff1a;直接或者间接调用自身的函数叫 递归函数: 边界条件/递归出口&#xff1a;递归调用的终止条件。避免出现死循环或者爆栈的情况。//报错显…

【python】图像、音频、视频等文件数据采集

【python】图像、音频、视频等文件数据采集 先安装所需要的工具一、Tesseract-OCRTesseract-OCR环境变量设置验证是否配置成功示例语言包下载失败 二、ffmpeg验证是否安装成功示例 先安装所需要的工具 一、Tesseract-OCR Tesseract是一个 由HP实验室开发 由Google维护的开源的…

【青牛科技】2K02 电动工具专用调速电路芯片描述

概述&#xff1a; 2K02 是电动工具专用调速电路。内置稳压电路&#xff0c;温度系数好&#xff0c;可以调节输出频率以及占空比的振荡输出&#xff0c;广泛的应用于小型电钻&#xff0c;割草机等工具。 主要特点&#xff1a; ● 电源电压范围宽 ● 占空比可调 ● 温度系数好 …

内网穿透步骤

步骤 第一次需要验证token window和linux的方法不同。 然后 启动 cpolar 服务&#xff1a; 在命令窗口中输入 cpolar.exe htttp 8080&#xff0c;启动内网穿透服务。确保命令窗口保持开启状态&#xff0c;以维持穿透效果。 cpolar.exe hhttp 8080 成功后 注意事项 命令窗口…

FreeRTOS之vTaskStartScheduler实现分析

FreeRTOS之vTaskStartScheduler实现分析 1 FreeRTOS源码下载地址2 函数接口2.1 函数接口2.2 函数参数简介3 vTaskDelete的调用关系3.1 调用关系3.2 调用关系示意图 4 函数源码分析4.1 vTaskStartScheduler4.2 prvCreateIdleTasks4.2.1 prvCreateIdleTasks4.2.2 xTaskCreate 4.3…

基于群晖搭建个人图书架-TaleBook based on Docker

前言 在群晖Container Manager中部署失败&#xff0c;转通过ssh部署。 一、准备工作 名称备注群晖SSH“终端机和SNMP”中启用SSH软件secureCRT等docker-compose.ymlGithub下载并修改 二、过程 2.1 创建本地文件夹 本地路径为&#xff1a; /docker/Calibre/data 2.2 下载d…

Ubuntu24.04初始化教程(包含基础优化、ros2)

将会不断更新。但是所有都是基础且必要的操作。 为重装系统之后的环境配置提供便捷信息来源。记录一些错误的解决方案。 目录 构建系统建立系统备份**Timeshift: 系统快照和备份工具****安装 Timeshift****使用 Timeshift 创建快照****还原快照****自动创建快照** 最基本配置换…

【论文笔记】A Token-level Contrastive Framework for Sign Language Translation

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: A Token-level Contrastiv…

yolov5 解决:export GIT_PYTHON_REFRESH=quiet

当我们在第一次运行YOLOv5中的train.py程序时&#xff1a;可能会出现以下报错&#xff1a; This initial warning can be silenced or aggravated in the future by setting the $GIT_PYTHON_REFRESH environment variable. Use one of the following values: - quiet|q|silen…

基于springboot中小型制造企业质量管理系统源码和论文

信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自古以来的…

【实验13】使用预训练ResNet18进行CIFAR10分类

目录 1 数据处理 1.1 数据集介绍 1.2数据处理与划分 2 模型构建- Pytorch高层API中的Resnet18 3 模型训练 4 模型评价 5 比较“使用预训练模型”和“不使用预训练模型”的效果&#xff1a; 6 模型预测 7 完整代码 8 参考链接 1 数据处理 1.1 数据集介绍 数据规模&…

Java之链表1

文章目录 1. 链表1.11.2 链表的概念及其结构1.3 自己实现一个链表 1. 链表 1.1 之前我们学习了 顺序表ArrayList&#xff0c;并自己实现了 ArrayList &#xff0c;发现它在删除元素和添加元素时很麻烦&#xff0c;最坏的情况时&#xff0c;需要将所有的元素移动&#xff0c;因…

二分搜索(三)x的平方根

69. x 的平方根 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2…

AI开发-数据可视化库-Seaborn

1 需求 概述 Seaborn 是一个基于 Python 的数据可视化库&#xff0c;它建立在 Matplotlib 之上。其主要目的是使数据可视化更加美观、方便和高效。它提供了高层次的接口和各种美观的默认主题&#xff0c;能够帮助用户快速创建出具有吸引力的统计图表&#xff0c;用于数据分析和…

使用docker-compose部署搜索引擎ElasticSearch6.8.10

背景 Elasticsearch 是一个开源的分布式搜索和分析引擎&#xff0c;基于 Apache Lucene 构建。它被广泛用于实时数据搜索、日志分析、全文检索等应用场景。 Elasticsearch 支持高效的全文搜索&#xff0c;并提供了强大的聚合功能&#xff0c;可以处理大规模的数据集并进行快速…

LeetCode—74. 搜索二维矩阵(中等)

仅供个人学习使用 题目描述&#xff1a; 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true…

Cento7 紧急模式无法正常启动,修复home挂载问题

Centos 7 开机失败进入紧急模式[emergency mode]&#xff0c;解决方案。 通过journalctl -xb查看启动日志&#xff0c;定位发现/home目录无法正常挂载。 退出启动日志检查&#xff0c;进行修复。 进行问题修复 # 修复挂载问题 mkdir /home mount /dev/mapper/centos-home /ho…