C++(18)——智能指针unique_ptr

2023-11-01

简介

unique_ptr 是 C++ 11 提供的用于防止内存泄漏的智能指针中的一种实现,独享被管理对象指针所有权的智能指针。unique_ptr对象包装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联的原始指针。

unique_ptr对象始终是关联的原始指针的唯一所有者,我们无法复制unique_ptr对象,它只能移动。

首先我们利用STL提供的unique_ptr管理对象时,不能完成下面框出的操作:
在这里插入图片描述

上述操作受限与否的原理是什么?和之前一样,我们模仿源码的逻辑,仿写unique_ptr,看看unique_ptr的实现原理:

先来实现一下unqiue_ptr的默认删除器
在这里插入图片描述
由于每个unique_ptr对象都是原始指针的唯一所有者,因此在其析构函数中它直接删除关联的指针,不需要任何参考计数。

//泛化模板类
template<class _Ty>
class Mydeletor
{
    Mydeletor() = default;
    void operator()(_Ty *ptr)const
    {
        if(ptr != nullptr)
        {
            delete ptr;
        }
    }
};

//部分特化
template<class _Ty>
class Mydeletor<_Ty[]>
{
    Mydeletor() = default;
    void operator()(_Ty *ptr)const
    {
        if(ptr != nullptr)
        {
            delete[] ptr;
        }
    }
};

继续完成unqiue_ptr的设计

template<class _Ty,class _Dx = Mydeletor<_Ty>>//给出一个删除单个对象的删除器
class my_unique_ptr
{
//C11新写法
using pointer = _Ty*;    //     typedef _Ty pointer;
using element_type = _Ty;//     typedef _Ty element_type;
using delete_type = _Dx; //     typedef _Dx delete_type;
private:
    _Ty* _Ptr;
    _Dx _myDeletor;
public:
    my_unique_ptr(const my_unique_ptr &) = delete;
    my_unique_ptr & operator=(const my_unique_ptr &) = delete;

    my_unique_ptr(pointer _p = nullptr):_Ptr(_p){}
    ~my_unique_ptr()
    {
        if(_Ptr != nullptr)
        {
            _myDeletor(_Ptr);//对象()——>调动仿函数
            _Ptr = nullptr;
        }
    }

    //移动构造
    my_unique_ptr(my_unique_ptr && _Y)
    {
        _Ptr = _Y._Ptr;
        _Y._Ptr = nullptr;
    }

    //移动赋值
    my_unique_ptr & operator=(my_unique_ptr && _Y)
    {
        if(this == &_Y)return *this;

        reset(_Y.release());
        //if(_Ptr != nullptr)
        //{
        //    _myDeletor(_Ptr);
        //}
        //_Ptr = _Y._Ptr;
        //_Y._Ptr = nullptr;
        return *this;
    }

    //返回删除器对象
    _Dx & get_deletor() 
    {
        return _myDeletor;
    }

    const _Dx & get_deletor() const 
    {
        return _myDeletor;
    }

    //解引用指向被管理对象的指针
    _Ty & operator*()const
     {
         return *_Ptr;
     }
    pointer operator->()const
    {
        return _Ptr;//&**this
    }
    //返回指向管理对象的指针
    pointer get() const
    {
        return _Ptr;
    }

    //测试当前_Ptr指向是否为nullptr
    operator bool() const//强转bool
    {
        return _Ptr != nullptr;
    }
    //my_unqiue_ptr<int> op;
    //if(op){}//——>if(op.operator bool()){}

    pointer release()
    {
        _Ty *old = _Ptr;
        _Ptr = nullptr;
        return old;
    }

    void reset(pointer _P = nullptr)
    {
        pointer old = _Ptr;
        _Ptr = _P;
        if(old != nullptr)
        {
            _myDeletor(old);//get_deletor(old);
        }
    }

    void Swap(my_unique_ptr _Y)
    {
        std::swap(_Ptr,_Y.Ptr);
        std::swap(_myDeletor,_Y._myDeletor);
    }
};

//部分特化:处理数组
class my_unique_ptr<_Ty[],_Dx>
{
//C11新写法
using pointer = _Ty*;    //     typedef _Ty pointer;
using element_type = _Ty;//     typedef _Ty element_type;
using delete_type = _Dx; //     typedef _Dx delete_type;
private:
    _Ty* _Ptr;
    _Dx _myDeletor;
public:
    my_unique_ptr(const my_unique_ptr &) = delete;
    my_unique_ptr & operator=(const my_unique_ptr &) = delete;

    my_unique_ptr(pointer _p = nullptr):_Ptr(_p){}
    ~my_unique_ptr()
    {
        if(_Ptr != nullptr)
        {
            _myDeletor(_Ptr);//对象()——>调动仿函数
            _Ptr = nullptr;
        }
    }

    //移动构造
    my_unique_ptr(my_unique_ptr && _Y)
    {
        _Ptr = _Y._Ptr;
        _Y._Ptr = nullptr;
    }

    //移动赋值
    my_unique_ptr & operator=(my_unique_ptr && _Y)
    {
        if(this == &_Y)return *this;

        reset(_Y.release());
        //if(_Ptr != nullptr)
        //{
        //    _myDeletor(_Ptr);
        //}
        //_Ptr = _Y._Ptr;
        //_Y._Ptr = nullptr;
        return *this;
    }

    //返回删除器对象
    _Dx & get_deletor() 
    {
        return _myDeletor;
    }

    const _Dx & get_deletor() const 
    {
        return _myDeletor;
    }

    //解引用指向被管理对象的指针
    _Ty & operator*()const
     {
         return *_Ptr;
     }
    pointer operator->()const
    {
        return _Ptr;//&**this
    }
    //返回指向管理对象的指针
    pointer get() const
    {
        return _Ptr;
    }

    //检查是否有关联的被管理对象
    operator bool() const//强转bool
    {
        return _Ptr != nullptr;
    }
    //my_unqiue_ptr<int> op;
    //if(op){}//——>if(op.operator bool()){}

    pointer release()
    {
        _Ty *old = _Ptr;
        _Ptr = nullptr;
        return old;
    }

    void reset(pointer _P = nullptr)
    {
        pointer old = _Ptr;
        _Ptr = _P;
        if(old != nullptr)
        {
            _myDeletor(old);//get_deletor(old);
        }
    }

    void Swap(my_unique_ptr _Y)
    {
        std::swap(_Ptr,_Y.Ptr);
        std::swap(_myDeletor,_Y._myDeletor);
    }

    _Ty & operator[](size_t _Idx) const
    {
        return _Ptr[_Idx];
    }
};

template<class _Ty,class ... _Type>//可变参
my_unique_ptr<_Ty> my_make_unique(_Type&& ... arys)
{
    return my_unique_ptr<_Ty>(new _Ty(_arys...)); 
}

unique_ptr具有->*运算符重载符,因此它可以像普通指针一样使用。
关于unique_ptr的使用,可以参考这一篇博客:
C++ 智能指针 unique_ptr 详解与示例

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

C++(18)——智能指针unique_ptr 的相关文章

  • .NET 单点登录

    我一直在尝试使用 C 为 NET Web 应用程序实现 WEB SSO 服务提供程序插件 我将使用 shibboleth 身份提供商 我已经使用 OpenSAML 库为 java 应用程序实现了相同的功能 我想知道在 NET 应用程序中使用
  • 如何在特定时间以毫秒精度触发 C# 函数?

    我有两台计算机 它们的时间通过 NTP 同步 确保时间仅相差几毫秒 其中一台计算机将通过 TCP 向另一台计算机发送一条消息 以在两台计算机上的未来指定时间启动某个 c 函数 我的问题是 如何在特定时间以毫秒精度 或更好 触发 C 中的函数
  • 平滑手绘曲线

    我有一个允许用户绘制曲线的程序 但这些曲线看起来不太好 它们看起来摇摇欲坠 而且是手绘的 所以我想要一种能够自动平滑它们的算法 我知道平滑过程中存在固有的模糊性 因此它不会每次都完美 但这种算法似乎确实存在于多个绘图包中 并且它们工作得很好
  • 为什么子函数不销毁GtkWindow?

    这是我的代码 void window first void enter window2 GtkWidget w gpointer data void quit GtkWidget w gpointer data void quit int
  • 嵌入资源文件的路径

    我的资源文件中有一个图标 我想引用它 这是需要图标文件路径的代码 IWshRuntimeLibrary IWshShortcut MyShortcut MyShortcut IWshRuntimeLibrary IWshShortcut W
  • ASP.NET - 在 RenderContent 调用中将事件处理程序添加到 Repeater 内的 LinkBut​​ton

    我有一个加载自定义用户控件的 Sharepoint WebPart 用户控件包含一个 Repeater 而 Repeater 又包含多个 LinkBut ton 在 Web 部件的 RenderContent 调用中 我有一些用于添加事件处
  • Monotouch全局异常处理

    我在野外发现了一只令人讨厌的虫子 但我无法确定它的具体情况 有没有办法拥有全局 Try Catch 块 或者有办法处理 Monotouch 中未处理的任何异常 我可以包起来吗UIApplication Main args 在 try cat
  • 对作为函数参数传递的指针使用删除

    删除作为函数参数传递的指针是否可以 并且合法 如下所示 include
  • 如何减少 MinGW g++ 编译器生成的可执行文件的大小?

    我有一个简单的 Hello world C 程序 在 Win XP 下由 MinGW g 编译器编译为 500kB 可执行文件 有人说这是由于iostream的库和静态链接libstdc dll Using s链接器选项有点帮助 减少了 5
  • 调用异步方法在视图模型的构造函数中加载数据有警告

    我的视图包含一个 ListView 它显示来自互联网的一些数据 我创建一个异步方法来加载数据并在我的视图模型的构造函数中调用该方法 它有一个警告提示我现在使用await关键字 还有其他解决方案可以在构造函数中异步加载数据吗 有几种可以应用的
  • 您对“大规模 C++ 软件设计”的看法 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 正在阅读亚马逊评论 https rads stackoverflow com amzn click com 0201633620 and ACC
  • C#:自定义转换为值类型

    是否可以将自定义类转换为值类型 这是一个例子 var x new Foo var y int x Does not compile 是否有可能实现上述情况 我需要超载一些东西吗Foo 您将必须重载强制转换运算符 public class F
  • DataGridView 行背景颜色没有改变

    我想根据加载时的特定条件更改 DGV 行的背景颜色 即使在 Windows 窗体中也是如此 但我看不到任何 DGV 行的颜色有任何变化 谁能告诉我如何解决这个问题 private void frmSecondaryPumps Load ob
  • 如何从 Access 数据库中读取“是/否”值作为布尔值?

    帮我找回YES NO来自 MS Access 的布尔格式数据类型 我尝试解析它 但它总是返回 false 更新 实际上不是问题抱歉 它确实接受 YES NO 作为布尔值 OleDbconnection dbConnect new OleDb
  • “1个未解决的外部”C++

    我已经检查了所有文件之间的连接以及类和函数定义 但每次我尝试运行我的程序时 它都会阻止我并告诉我它有 1 个未解析的外部 该程序应该打开多个文件 一个 学生 文件和一个 成绩 文件 从中读取数据 然后使用 查询文件 来查找数据 找到查询中要
  • Xcode 7 调试器不会中断内联标头函数

    过去五年我一直在各种 C 项目中使用 Xcode 没有出现这个问题 今天 我打开了一个较旧的项目 大约 2 年前 并尝试通过在该函数中放置一个活动断点来调试头文件中的内联函数 由于某种原因 调试器不会中断此代码 但是 如果我在调用该函数的
  • 当我的进程被终止时到底会发生什么?

    我有一个包含本机代码和托管代码的混合进程 在 Windows Server 2003 上运行 当我从进程资源管理器中终止进程时 它会进入 100 cpu 的状态 并在消失之前保持这种状态一段时间 有时甚至 10 分钟 在此期间我无法 杀死
  • Boost.asio和异步链,unique_ptr?

    我对异步编程不太熟悉 我有一个问题 我的问题如下 给出 boost asio 中 C 11 的 echo server 示例 http www boost org doc libs 1 60 0 doc html boost asio ex
  • 实体框架代码首次日期字段创建

    我正在使用实体框架代码优先方法来创建我的数据库表 下面的代码 创建一个DATETIME数据库中的列 但我想创建一个DATE柱子 DataType DataType Date DisplayFormatAttribute ApplyForma
  • 如何使用 C# 为 azure devops 变量赋值

    我有 selenium C 测试脚本 可以从浏览器获取令牌 我有两个 azure devops 任务 一个用于执行 selenium 测试 另一个用于执行 API 测试 我想将 selenium 测试获取的令牌传递给 API 测试执行任务

随机推荐

  • flink连接kafka报:org.apache.kafka.common.errors.TimeoutException

    测试flink1 12 7 连接kafka package org test flink import org apache flink api common serialization SimpleStringSchema import
  • 用chatgpt超级写手批量制作抖音带货文案并直接SEO霸屏

    带货文案怎么写 最好的解决方案就是学习同行 简版流程 通过抖音热点宝 手机端 的种草视频 或者抖音筛选出最多点赞 半年内的带货视频 提取出带货文案 然后用chatgpt直接改写一下带货文案 也可以根据抖音商城的爆款商品 提炼出卖点 然后利用
  • HTML5-表单

    HTML5 表单 一 Form 1 action 属性 action 属性用于指定表单提交时向何处发送表单数据 即需要发送的服务器地址
  • linux bash如何判断脚本命令参数是否存在

    linux bash处理较简单的参数 如 test sh 10 而很少使用 test n 10这种带选项的方式 典型用法为 bin bash if x 1 x then 有参数 else then 没有参数 fi 为什么要使用 x 1 x
  • MII接口及应用

    MII是英文Medium Independent Interface的缩写 翻译成中文是 介质独立接口 该接口一般应用于以太网硬件平台的MAC层和PHY层之间 MII接口的类型有很多 常用的有MII RMII SMII SSMII SSSM
  • sink 写入本地文件(八)

    sink 写入本地文件 2 4 Sink 2 4 1 将数据写入文件 File Sink 2 4 Sink Flink 没有类似于spark中 foreach 方法 让用户进行迭代的操作 虽有对外的输出操作都要利用Sink完成 最后通过类似
  • 软件工程 第一次随堂练习

    以下答案是经过人工智能生成 个人理解得出的答案 若有不同见解 请在评论区留言或私信 说明下列需求分别属于下面的哪种类型 为什么 A 业务需求 B 用户需求 C 系统级 功能 需求 D 性能需求 E 质量需求 F 约束 G 对外接口 H 数据
  • linux的aix下的makefile参考

    一 详解 1 简单模板makefile CC OBJS CFLAGS TARGET all TARGET TARGET OBJS CC CFLAGS o OBJS SUFFIXES o h SUFFIXES cpp o cpp o CC c
  • APP首次进入,弹出服务协议和隐私政策

    app上应用市场里需要几个条件 需要第一次下载并进入首页前展示用户协议和隐私政策弹窗提醒 以及在应用内版块有常驻入口 就是应用里有可以看到这个协议的版块 登录或者注册页面也需要有同意服务协议和隐私政策的提醒 在上个项目上线时候遇到andro
  • 服务器管理口安装系统,管理口安装服务器操作系统

    管理口安装服务器操作系统 内容精选 换一换 如果Windows操作系统云服务器未安装密码重置插件 可以参见本节内容重新设置密码 本节操作介绍的方法仅适用于修改Windows本地账户密码 不能修改域账户密码 Linux操作系统请参见重置Lin
  • Golang 从零开始实现多人聊天室(五)开发前奏-目录结构优化

    系列文章目录 跟着 猫猫学Golang 快人一步 系列初开 跟着我走进Go 语言的世界里 系列目录 Golang 从零开始实现多人聊天室 一 服务端监听 Golang 从零开始实现多人聊天室 二 客户端访问 Golang 从零开始实现多人聊
  • 图像阈值cv2.threshold

    图像阈值 图像阈值函数 图像阈值函数 ret dst cv2 threshold src thresh maxval type src 输入图 只能输入单通道图像 通常来说为灰度图 dst 输出图 thresh 阈值 maxval 当像素值
  • (如何安装pytorch详细教程!!!)全面讲解安装Anaconda+CUDA+PyTorch

    之前安装了CUDA 与Pytorch 但是当把自己的数据放到GPU上训练的时候 代码部分已经写清楚放到CUDA上 发现GPU的占用率很低 CPU的占用率高达90 后来发现是显卡的驱动与自己安装的CUDA并不匹配 pytorch与cuda的版
  • 三组计算机局域网组网方案,怎么建立一个可以互相联机的局域网

    都是xp的就好办了 在网上邻居里 先设置家庭或小型办公网络 然后添加邻居就可以了 你试下 不行的话 下面的资料你参考下 goodluck 家庭或小型办公室 如果有两台或更多的计算机 很自然地希望将他们组成一个网络 为方便叙述 以下约定将其称
  • kubernetes集群实战--master节点及node节点的部署搭建(二)

    kubernetes集群的安装部署 1 基础环境部署 准备三台虚拟机 主机名 IP地址 角色 k8s master 192 168 100 8 master node k8s node1 192 168 100 9 node1 k8s no
  • 使用ppocr突然退出问题

    本次使用conda装了一个cuda10 2版本的paddleocr 然后所有的环境检查没问题 使用paddle自带的检查代码 输出提醒paddle可以正常使用 gt gt gt import paddle gt gt gt paddle u
  • QT 鼠标事件及labe显示设置总结

    qt鼠标事件总结 转 1 QMouseEvent中的坐标 QMouseEvent中保存了两个坐标 一个是全局坐标 当然另外一个是局部坐标 全局坐标 globalPos 即是桌面屏幕坐标 screen coordinates 这个跟windo
  • Edge浏览器查看请求头(2022)

    目录 如何查看 使用公开的 如何查看 OK如果大家找不到的话可以用下面的这些在网上已经公开的请求头 使用公开的 Mozilla 5 0 Windows NT 10 0 Win64 x64 AppleWebKit 537 36 KHTML l
  • 报错 java.lang.NoClassDefFoundError: Lcom/sun/tools/javac/util/List;

    解决办法 全局搜索javac 找到引用的地方 import com sun tools javac util List 把它删除 重新引用 import java util List 原因 jar包引用错误
  • C++(18)——智能指针unique_ptr

    简介 unique ptr 是 C 11 提供的用于防止内存泄漏的智能指针中的一种实现 独享被管理对象指针所有权的智能指针 unique ptr对象包装一个原始指针 并负责其生命周期 当该对象被销毁时 会在其析构函数中删除关联的原始指针 u