C++智能指针之unique_ptr(保姆级教学)

news2025/2/28 22:17:11

目录

unique_ptr

概述

涉及程序

初始化

手动初始化

std::make_unique函数(C++14)

unique_ptr常规操作

不支持操作:该指针不支持拷贝和赋值操作;所以不能拷贝到容器里

移动语义std::move();

release();

reset();

*解应用

get();

指定删除器

unique_ptr和shared_ptr指定删除器时的区别

unique_ptr尺寸


unique_ptr

概述

独占式指针(专属所有权),同一时刻,只能有一个unique_ptr指向这个对象;当指针销毁,指向的对象也销毁;因此该指针不支持拷贝和赋值操作,也不存在引用计数。

涉及程序

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

class A
{
public:
    A()
    {
        cout << "A" << endl;
    }

    A(int num) : m_num(num)
    {
        cout << "A int" << endl;
    }

    A(const A &&other) : m_num(other.m_num)
    {
        cout << "A move int" << endl;
    }

    ~A()
    {
        cout << "~A" << endl;
    }

public:
    int m_num;
};

void mydelete(A *p)
{
    delete[] p;
}
int main(int argc, char const *argv[])
{
#if 0
    unique_ptr<int> p(new int(5));            //可以指定删除器
    unique_ptr<int> p2 = make_unique<int>(6); //不可用指定删除器
    // unique_ptr<int>p2 = p;

    //指定删除器
    // unique_ptr<A[]>pa(new A[3]);
    using p_delete = void (*)(A * p);
    unique_ptr<A, p_delete> pa(new A[3], mydelete);
    unique_ptr<A>ptr(new A());

    vector<unique_ptr<A>>vp;
    // vp.push_back(pa);
    // vp.push_back(ptr);

    cout << sizeof(pa) <<endl;
    cout << sizeof(ptr) <<endl;

    // shared_ptr<A> pa(new A[3], mydelete);
    // shared_ptr<A> ptr(new A(5));
    // vector<shared_ptr<A>>vp;
    // vp.push_back(pa);
    // vp.push_back(ptr);

//release():放弃智能指针的控制权,将该指针置为nullptr,返回的是裸指针
    unique_ptr<int>pi(new int(5));
    int *temp = pi.release();
    if(pi = nullptr)
    {
        cout <<"pi is nullptr"<<endl;
    }
    cout << *temp<<endl;
//reset() reset(参数)
    unique_ptr<int>p2(new int(5));
    p2.reset();
    p2.reset(new int(6));
    cout << *p2<<endl;
#endif
    //移动语义std::move()
    unique_ptr<A> ptr(new A(5));
    unique_ptr<A> &&rptr = std::move(ptr);
    cout << ptr->m_num <<endl;
    cout << rptr->m_num <<endl;
    
    return 0;
}

初始化

手动初始化

unique_ptr p;或unique p(new int(5))

std::make_unique函数(C++14)

注:生成的指针不支持指定删除器语法

unique_ptr常规操作

不支持操作:该指针不支持拷贝和赋值操作;所以不能拷贝到容器里

不支持拷贝:

不支持赋值:

无法拷贝到容器

移动语义std::move();

使用右值引用可以进行赋值

release();

放弃对指针的控制权,将该指针置nullptr,返回裸指针;

注:返回的裸指针手动释放(防止内存泄漏)或者可以初始化另一个指针

reset();

  • reset()无参使用:若该智能指针是独占某个对象,则释放该对象,并将智能指针置nullptr;
  • reset()代参使用:若该智能指针是独占某个对象,则释放该对象,并将该指针指向新对象;

实例:p.reset();p.reset(new int());

*解应用

获得智能指针指向的对象,并对其操作;

get();

考虑到有些函数参数是裸指针并不是智能指针,所以需要将智能指针转化为裸指针;

获得智能指针中保存的指针(裸指针);

注:获得裸指针要小心使用,因为智能指针一旦释放,裸指针也就失效;

指定删除器

语法:unique_ptr 智能指针变量名

以下图为例,当指针指向一段连续的数组空间时,会产生内存泄漏

一般的解决办法是指定数组(加“[ ]”)

自定义删除函数

unique_ptr的删除器需要我们指定删除器的类型,当我们像shared_ptr一样直接传入删除器就会产生报错,如下图所示:

指定删除器类型操作如下图所示,运行结果正常

注:unique_ptr的删除器类型可以任意定义,而shared_ptr的删除器类型必须是void类型

unique_ptr和shared_ptr指定删除器时的区别

区别1:unique_ptr在使用时必须要指定删除器的类型,而shared_ptr不需要指定

区别2:

  • 同类型的shared_ptr拥有不同的删除器,那么这些shared_ptr仍然是相同类型的

根据容器的特性,类型相同的变量可以存放在同一个容器中,我们使用vector容器成功验证了shared_ptr,如下图所示

  • 而指定不同删除器会导致不同类型的unique_ptr,因为unique_ptr的尺寸会发生变化

通过输出指针的大小,就可以发现不同删除器的unique_ptr的大小都不一样

但不能通过push_back插入到容器中的操作来验证,因为push_back是通过拷贝的操作将变量添加到容器中,而unique_ptr不支持拷贝操作

unique_ptr尺寸

unique_ptr的尺寸和裸指针一样大,但是指定自定义删除函数会影响尺寸大小;

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

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

相关文章

【计算机网络】 子网划分

文章目录 IP地址分类子网掩码网关广播地址非默认子网掩码子网划分常见问题 IP地址分类 学会十进制和二进制的相互转换可以很快速的有规律的记住 子网掩码 又叫网络掩码&#xff0c;地址掩码&#xff0c;子网络遮罩&#xff0c;就是说把子网络遮起来&#xff0c;不让外界窥探到…

“安全即服务”为网络安全推开一道门

8月30日&#xff0c;三六零&#xff08;下称“360”&#xff09;集团发布了2023年半年报&#xff0c;其中安全业务第二季度收入6.54亿元&#xff0c;同比增长98.76%&#xff0c;环比增长157.16%&#xff0c;安全第二增长曲线已完全成型&#xff01;特别值得一提的是&#xff0c…

【Unittest】Requests实现小程序项目接口测试

文章目录 一、搭建接口测试框架二、初始化日志三、定义全局变量四、封装接口五、编写测试用例六、生成测试报告 一、搭建接口测试框架 目录结构如下。 二、初始化日志 在utils.py文件中编写如下如下代码&#xff0c;初始化日志。 # 导入app.py全局变量文件 import app import l…

基于Zookeeper搭建Kafka高可用集群(实践可用)

目录 一、Zookeeper集群搭建 1.1 下载 & 解压 1.2 修改配置 1.3 标识节点 1.4 启动集群 1.5 集群验证 二、Kafka集群搭建 2.1 下载解压 2.2 拷贝配置文件 2.3 修改配置 2.4 启动集群 2.5 创建测试主题 2.6 写入数据测试 一、Zookeeper集群搭建 为保证集群高可…

SV中的随机化约束

1.多个变量相互依赖&#xff0c;如何进行随机化&#xff1f; 采用solve before &#xff08;1&#xff09;constraint c_valid_write_data {solve access_type before data;solve burst_length before data;(access_type TVIP_AXI_WRITE_ACCESS) -> data.size() burst…

算法通过村第五关-队列和Hash黄金笔记|LRU的设计与实现

文章目录 前言1. LRU的含义2. Hash双向链表实现LRU总结 前言 提示&#xff1a;我曾如此渴望命运的波澜&#xff0c;到最后才发现&#xff1a;人生最曼妙的风景&#xff0c;竟是内心的淡定从容。 我们层如此盼望世界的认可&#xff0c;到最后才知道&#xff1a;世界是自己&#…

01-Kafaka

1、Kafka 2 的安装与配置 1、上传kafka_2.12-1.0.2.tgz到服务器并解压&#xff1a; tar -zxf kafka_2.12-1.0.2.tgz -C /opt 2、配置环境变量并更新&#xff1a; 编辑profile配置文件&#xff1a; vim /etc/profile #设置kafka的环境变量export KAFKA_HOME/opt/kafka_2.1…

【ESP32--FreeRTOS 任务间的同步与通信】

本文主要记录【ESP32–FreeRTOS 任务间的同步与通信】的学习记录&#xff0c;邮件&#xff0c;信号量&#xff0c;事件组的使用和优缺点以及应用场景 &#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是喜欢记录零碎知识点的小菜鸟。&#x1f6…

软件测试之随机测试

目录 一、作随机测试之前的一些前提条件 二、随机测试功能点的选取 三、功能点的随机测试 在软件测试中除了根据测试用例和测试说明书进行功能测试外&#xff0c;还需要进行随机测试&#xff08;Ad-hoc testing&#xff09;&#xff0c;随机测试是没有书面测试用例、记录期望…

【算法】插入排序

插入排序 插入排序代码实现代码优化 排序&#xff1a; 排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a; 假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&…

【算法】归并排序 详解

归并排序 详解 归并排序代码实现1. 递归版本2. 非递归版本 排序&#xff1a; 排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a; 假定在待排序的记录序列中&#xff0c;存在多个具有相…

dpkt 处理linux cooked capture

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

CUDA小白 - NPP(4) 图像处理 Data Exchange and Initialization(1)

cuda小白 原始API链接 NPP GPU架构近些年也有不少的变化&#xff0c;具体的可以参考别的博主的介绍&#xff0c;都比较详细。还有一些cuda中的专有名词的含义&#xff0c;可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》 常见的NppStatus&#xf…

QT 初识多线程

1.QThread线程基础 QThread是Qt线程中有一个公共的抽象类&#xff0c;所有的线程类都是从QThread抽象类中派生的&#xff0c;需要实现QThread中的虚函数run(),通过start()函数来调用run函数。 void run&#xff08;&#xff09;函数是线程体函数&#xff0c;用于定义线程的功能…

借助CIFAR10模型结构理解卷积神经网络及Sequential的使用

CIFAR10模型搭建 CIFAR10模型结构 0. input : 332x32&#xff0c;3通道32x32的图片 --> 特征图(Feature maps) : 3232x32即经过32个35x5的卷积层&#xff0c;输出尺寸没有变化&#xff08;有x个特征图即有x个卷积核。卷积核的通道数与输入的通道数相等&#xff0c;即35x5&am…

01-从JDK源码级别剖析JVM类加载机制

1. 类加载运行全过程 当我们用java命令运行某个类的main函数启动程序时&#xff0c;首先需要通过类加载器把主类加载到JVM。 public class Math {public static final int initData 666;public static User user new User();public int compute() { //一个方法对应一块栈帧…

整理mongodb文档:事务(一)

个人博客 整理mongodb文档:事务(一) 原文链接&#xff0c;个人博客 求关注&#xff0c;本文主要讲下怎么在mongose下使用事务&#xff0c;建议电脑端看 文章概叙 本文的开发环境为Nodejs&#xff0c;在‘单机模式’讲解最基本的事务概念。并没有涉及分片以及集群&#xff0…

《向量数据库指南》——AI原生向量数据库Milvus Cloud 2.3新功能

New Feature Upsert 功能 支持用户通过 upsert 接口更新或插入数据。已知限制,自增 id 不支持 upsert;upsert 是内部实现是 delete + insert所以性能上会有一定损耗,如果明确知道是写入数据的场景请继续使用 insert。 Range Search 功能 支持用户通过输入参数指定 search 的…

TortoiseGit设置作者信息和用户名、密码存储

前言 Git 客户端每次与服务器交互&#xff0c;都需要输入密码&#xff0c;但是我们可以配置保存密码&#xff0c;只需要输入一次&#xff0c;就不再需要输入密码。 操作说明 在任意文件夹下&#xff0c;空白处&#xff0c;鼠标右键点击 在弹出菜单中按照下图点击 依次点击下…

LLVM 与代码混淆技术

项目源码 什么是 LLVM LLVM 计划启动于2000年&#xff0c;开始由美国 UIUC 大学的 Chris Lattner 博士主持开展&#xff0c;后来 Apple 也加入其中。最初的目的是开发一套提供中间代码和编译基础设施的虚拟系统。 LLVM 命名最早源自于底层虚拟机&#xff08;Low Level Virtu…