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

2023-11-12

目录

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的尺寸和裸指针一样大,但是指定自定义删除函数会影响尺寸大小;

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

C++智能指针之unique_ptr(保姆级教学) 的相关文章

  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 无限循环与无限递归。两者都是未定义的吗?

    无副作用的无限循环是未定义的行为 看here https coliru stacked crooked com view id 24e0a58778f67cd4举个例子参考参数 https en cppreference com w cpp
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 重载 (c)begin/(c)end

    我试图超载 c begin c end类的函数 以便能够调用 C 11 基于范围的 for 循环 它在大多数情况下都有效 但我无法理解和解决其中一个问题 for auto const point fProjectData gt getPoi
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • DotNetZip:如何提取文件,但忽略zip文件中的路径?

    尝试将文件提取到给定文件夹 忽略 zip 文件中的路径 但似乎没有办法 考虑到其中实现的所有其他好东西 这似乎是一个相当基本的要求 我缺少什么 代码是 using Ionic Zip ZipFile zf Ionic Zip ZipFile
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐

  • Eigen中的基本函数

    Eigen中的基本函数 Eigen中矩阵的定义 include
  • 微服务和分布式一些概念

    2 1分布式一些基本概念 2 1 1微服务概述 微服务 对应用程序而言 微服务架构风格 就像是把一个单独的应用程序开发为一套小服务 每个小服务运行在自己的进程中 并使用轻量级机制通信 通常是HTTP API 这些服务围绕业务能力来构建 并通
  • 创建线程池的七种方式

    在 Java 语言中 并发编程往往都是通过床架线程池来实现的 而线程池的创建方式也有很多种 每种线程池的创建方式都对应了不同的使用场景 总结来说线程池的创建可以分为两大类 通过 Executors 创建 通过 ThreadPoolExecu
  • Java Double类型出现科学计数法问题解决

    问题描述 Double num1 0 0004 问题分析 1 当数据足够小或者足够大时 Double会将数据自动变成科学计数法 解决办法 将Double类型先变成String类型 再将String类型变为BigDecimal即可 Doubl
  • Pycharm的git密码填错了的修改方法

    本篇文章主要讲解Pycharm的git密码填错了的修改方法 日期 2022年2月18日 作者 任聪聪 填写错误密码发现提交不了git 解决办法 步骤一 打开搜索框 步骤二 搜索控制面板 步骤三 打开面板 找到用户凭据管理 步骤四 点击管理w
  • 关掉linux ssh终端后,让程序继续执行的方法

    最近买了个树莓派 发现中移动的物联网云平台挺好 就想玩玩 用树莓派上自动获取温度上报到云端 通过web显示 测试时希望在ssh上执行完命令后 关闭电脑或者ssh命令行终端后 树莓派继续运行 1 使用 nohup 命令 说明 网上有的说输入下
  • vue3+vue3-video-player+vue3-danmaku实现直播和弹幕

    视频组件 vue3 video player 首先下载vue3 video player 官方文档 Vue3VideoPlay 下载 npm i vue3 video play save 在main ts js注册 import creat
  • MongoDB 基础入门

    MongoDB 是什么 MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统 由 C 编写的 MongoDB 提供了 面向文档 的存储方式 操作起来比较简单和容易 支持 无模式 的数据建模 可以存储比较复杂的数据类型
  • 030_Message消息提示

    1 Message消息提示 1 1 Message消息提示常用于主动操作后的反馈提示 与Notification的区别是后者更多用于系统级通知的被动提醒 1 2 Options 参数 说明 类型 可选值 默认值 message 消息文字 s
  • [JAVAee]spring-Bean对象的执行流程与生命周期

    执行流程 spring中Bean对象的执行流程大致分为四步 启动Spring容器 实例化Bean对象 Bean对象注册到Spring容器中 将Bean对象装配到所需的类中 启动Spring容器 在main方法中获取spring上下文对象并配
  • 算法分析与设计期末复习

    第一章 算法概述 1 算法 解决问题的一种方法或过程 由若干条指令组成的有穷指令 2 算法的性质 输入 有零个或多个输入 输出 有至少一个输出 确定性 每条指令是清晰的 无歧义的 有限性 每条指令的执行次数和时间都是有限的 3 算法与程序的
  • Win10下安装Intel Visual Fortran2019具体步骤及初始调试过程。

    相关程序安装包可以搜索微信公众号 火耳软件 他们的公众号上基本所有软件都能下载到 Win10下安装Intel Visual Fortran2019具体步骤及初始调试过程 先装Visual Studio2017 安装步骤省略 可在网上找到 再
  • eclipse异常类之自定义异常和assert

    1 在实际开发中 可以利用异常的处理机制来处理业务逻辑错误 就是使用自定义异常 例如用户名密码输入错误 自定义异常通常都是通过继承一个异常来实现 1 Throwable 2 Exception 3 RuntimeException 自定义异
  • Scrapy框架爬取新闻!

    步骤 创建一个scrapy项目 分析网页 完成代码 保存CSV文件 创建一个scrapy项目 本次爬取网站为 https wz sun0769 com app politics index cmd切换目录scrapy startprojec
  • 基于Netty手撕RPC框架

    基于Netty手撕RPC框架 文章目录 基于Netty手撕RPC框架 1 项目结构 2 api 3 provider 1 自定义注解 2 实现UserServiceInterface 3 NettyServer的客户端 4 NettyHan
  • 你参与的APP开发项目安全吗?

    Android将安全设计贯穿系统架构的各个层面 覆盖系统内核 虚拟机 应用程序框架层以及应用层各个环节 力求在开放的同时 也恰当保护用户的数据 应用程序和设备的安全 Android安全模型主要提供以下几种安全机制 进程沙箱隔离机制 应用程序
  • Qt内存管理(五) 自动垃圾回收机制

    实现自动垃圾回收的工具主要是Qt对象清理器 也就是QObjectCleanupHandler类 它监视多个QObject对象的生命期 当你想知道被别人拥有的QObject对象是否被删除时 这个类就派上了用场 例如引用 referencing
  • mysql报错:1264-Out of range value for column ‘字段‘ at row 1

    发现程序部分内容写不到数据库 于是来排查是否为数据库的问题 mysql数据库报错 1264 Out of range value for column guild leader id at row 1 如图所示 通过设计表 发现该字段的值超
  • java定位_java调用百度定位api服务获取地理位置示例

    package test import java io BufferedReader import java io IOException import java io InputStream import java io InputStr
  • C++智能指针之unique_ptr(保姆级教学)

    目录 unique ptr 概述 涉及程序 初始化 手动初始化 std make unique函数 C 14 unique ptr常规操作 不支持操作 该指针不支持拷贝和赋值操作 所以不能拷贝到容器里 移动语义std move releas