(C++) 智能指针指定删除器

news2024/11/15 2:17:40

文章目录

  • ⌚前言
    • ⏲️注意
  • ⌚unique_ptr
    • ⏲️说明
    • ⏲️实例
  • ⌚shared_ptr
    • ⏲️说明
    • ⏲️实例
  • ⌚拓展
    • ⏲️函数类型 & 函数指针类型
  • ⌚END
    • 🌟关注我

⌚前言

自C++11后,推出了三个智能指针。其中 unique_ptrshared_ptr可以指定删除器。

但两者的形式却不太一样,本文将带你了解两者的基础使用区别。

  • std::unique_ptr
  • std::shared_ptr
  • std::weak_ptr
  • std::make_unique, std::make_unique_for_overwrite - cppreference.com
  • std::make_shared, std::make_shared_for_overwrite - cppreference.com

⏲️注意

weak_ptr 是专门用来作为共享指针的使用权的,是一种零时的所有权,是没有删除器的。

make_xxx 是专门用于创建的,参数也很简单,就是直接转发到构造函数中,不附带指定删除器。(但不排除以后可能会添加兼容删除器的版本,但个人认为实现起来会比较麻烦)

本文不考虑数组版本的特化。

⌚unique_ptr

⏲️说明

类型声明

template<
    class T,
    class Deleter = std::default_delete<T>
> class unique_ptr;

构造声明

unique_ptr( pointer p, ? d) noexcept;
unique_ptr( pointer p, ? d) = delete;

构造拥有 p 的 std::unique_ptr 对象,以 p 初始化存储的指针,并按下列方式初始化删除器 D(依赖于 D 是否为引用类型)。

a) 若 D 是非引用类型 A,则签名是:

unique_ptr(pointer p, const A& d) noexcept; // (1)	(要求 Deleter 为不抛出可复制构造 (CopyConstructible) )
unique_ptr(pointer p, A&& d) noexcept;      // (2)	(要求 Deleter 为不抛出可移动构造 (MoveConstructible) )

b) 若 D 是左值引用类型 A&,则签名是:

unique_ptr(pointer p, A& d) noexcept;
unique_ptr(pointer p, A&& d) = delete;

c) 若 D 是左值引用类型 const A&,则签名是:

unique_ptr(pointer p, const A& d) noexcept;
unique_ptr(pointer p, const A&& d) = delete;

所有情况下删除器从 std::forward<decltype(d)>(d) 初始化。这些重载只有在 std::is_constructible<D, decltype(d)>::value 为 true 时才会参与重载决议。


说白了,就是模板的第二个删除器的参数类型要和构造函数的类型匹配。

比如,模板参数是左值引用A&,那构造函数也必须是左值引用A&

⏲️实例

其实只要知道原理,熟悉模板和函数对象的朋友很容易能构造出实例。

基于仿函数

#include <iostream>
#include <memory>

struct MyDeleter {
    void operator()(int* p) const {
        std::cout << __func__ << std::endl;
        delete p;
    }
};

int main() {
    MyDeleter del;

    std::unique_ptr<int, MyDeleter> p0(new int{100}, del);
    std::unique_ptr<int, MyDeleter> p1(new int{100}, MyDeleter{});
}

基于函数指针

#include <iostream>
#include <memory>

void del_fun(int* p) {
    std::cout << __func__ << std::endl;
    delete p;
}

int main() {
    std::unique_ptr<int, void (*)(int*)> p0(new int(100), [](int* ptr) {
        std::cout << __func__ << std::endl;
        delete ptr;
    });

    std::unique_ptr<int, void (*)(int*)>     p1(new int(100), del_fun);
    std::unique_ptr<int, decltype(&del_fun)> p2(new int(100), del_fun);
}

删除器为引用类型

#include <iostream>
#include <memory>

struct MyDeleter {
    // const 限定
    void operator()(int* p) const {
        std::cout << __func__ << std::endl;
        delete p;
    }
};

int main() {
    //! 指定为非引用类型
    std::unique_ptr<int, MyDeleter> p0(new int{100}, MyDeleter{});

    //! 指定为左值引用
    MyDeleter                        del;
    std::unique_ptr<int, MyDeleter&> p1(new int{100}, del);

    //! 指定类型为常引用
    // 注意 unique_ptr(pointer p, const A&& d) = delete;
    std::unique_ptr<int, const MyDeleter&> p2(new int{100}, del);

    //! 指定为右值应用
    // 错误,不能是右值引用
    // std::unique_ptr<int, MyDeleter&&> p3(new int{100}, MyDeleter{});
}

⌚shared_ptr

⏲️说明

类型声明

template< class T > class shared_ptr;

构造声明

当然shared_ptr的带有删除器的构造不止这一种,但是该构造是最具典型和功能单一的。

template< class Y, class Deleter >
shared_ptr( Y* ptr, Deleter d );

以指定的删除器 d 为删除器。表达式 d(ptr) 必须良构,拥有良好定义行为且不抛异常。d 的构造和从它复制并存储的删除器的构造必须不抛异常。

  • Deleter 必须可复制构造 (CopyConstructible) 。(C++17 前)
  • 若表达式 d(ptr) 非良构,或若 std::is_move_constructible_v 为 false,则这些构造函数也不参与重载决议。 (C++17 起)

总之shared_ptr的删除器不受类型干扰,而是在构造的时候确定,给了用户极大的自由度。

⏲️实例

可以方便的拷贝

#include <iostream>
#include <memory>

struct MyDeleter {
    void operator()(int* p) const {
        std::cout << __LINE__ << __func__ << std::endl;
        delete p;
    }
};

struct YourDeleter {
    void operator()(int* p) const {
        std::cout << __LINE__ << __func__ << std::endl;
        delete p;
    }
};

int main() {
    MyDeleter   my_del;
    YourDeleter your_del;

    std::shared_ptr<int> sp0(new int{100}, my_del);
    std::cout << *sp0 << std::endl;
    std::shared_ptr<int> sp1(new int{200}, your_del);
    std::cout << *sp1 << std::endl;

    // 类型是一样的,走拷贝赋值
    sp0 = sp1;
}

可以方便的由容器管理

#include <iostream>
#include <memory>
#include <vector>

struct MyDeleter {
    void operator()(int* p) const {
        std::cout << __LINE__ << __func__ << std::endl;
        delete p;
    }
};

struct YourDeleter {
    void operator()(int* p) const {
        std::cout << __LINE__ << __func__ << std::endl;
        delete p;
    }
};

int main() {
    std::shared_ptr<int> sp0(new int{100}, MyDeleter{});
    std::shared_ptr<int> sp1(new int{200}, YourDeleter{});

    // 统一使用vector进行管理
    std::vector<std::shared_ptr<int>> sp_arr;
    sp_arr.push_back(sp0);
    sp_arr.push_back(sp1);

    for (auto sp : sp_arr) {
        std::cout << *sp << std::endl;
    }
}

⌚拓展

⏲️函数类型 & 函数指针类型

#include <iostream>

int main() {
    // 指针类型
    using T0 = decltype(&main);
    // 函数类型
    using T1 = decltype(main);

    // 函数指针
    std::cout << typeid(&main).name() << std::endl;
    // 函数类型
    std::cout << typeid(main).name() << std::endl;
}

gcc mingw

PFivE
FivE

msvc

int (__cdecl*)(void)
int __cdecl(void)

⌚END

🌟关注我

关注我,学习更多C/C++,算法,计算机知识

B站:

👨‍💻主页:天赐细莲 bilibili

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

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

相关文章

【Canvas与艺术】红底白色压边五角星

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>精确压边五角星版本2</title><style type"text/css&qu…

Java IO模型深入解析:BIO、NIO与AIO

Java IO模型深入解析&#xff1a;BIO、NIO与AIO 一. 前言 在Java编程中&#xff0c;IO&#xff08;Input/Output&#xff09;操作是不可或缺的一部分&#xff0c;它涉及到文件读写、网络通信等方面。Java提供了多种类和API来支持这些操作。本文将从IO的基础知识讲起&#xff…

虚拟现实和增强现实技术系列—Expressive Talking Avatars

文章目录 1. 概述2. 背景介绍3. 数据集3.1 设计标准3.2 数据采集 4. 方法4.1 概述4.2 架构4.3 目标函数 5. 实验评测5.1 用户研究5.2 我们方法的结果5.3 比较与消融研究 1. 概述 支持远程协作者之间的交互和沟通。然而&#xff0c;明确的表达是出了名的难以创建&#xff0c;主…

两台电脑之间如何进行数据传输?两台电脑数据传输攻略

在数字化时代&#xff0c;电脑之间的数据传输变得日益重要。无论是个人用户还是企业用户&#xff0c;经常需要在不同的电脑之间共享或迁移数据。那么&#xff0c;两台电脑之间如何进行数据传输呢&#xff1f;本文将详细介绍两台电脑之间进行数据传输的几种常见方法&#xff0c;…

奖金+奖杯+荣誉证书 | FPGA硬件扑克牌比赛邀你参加

关键词&#xff1a;个人赛&#xff0c;随机发牌&#xff0c;比运气&#xff0c;还比设计&#xff0c;好玩又有趣 想用FPGA玩一场有趣的游戏吗&#xff1f;想检验自己的FPGA算法水平吗&#xff1f; “向日葵杯”全国教育仿真技术大赛——FPGA硬件扑克牌对抗赛等你来体验&#…

I can‘t link the chatbot model with react

题意&#xff1a;我无法将聊天机器人模型 chatbot 与React连接起来 问题背景&#xff1a; This is the model from flask import Flask, request, jsonify from flask_cors import CORS import json import nltk import numpy as np import random import pickle from time i…

英特尔终于宣布了解决CPU崩溃和不稳定性问题的方法,声称过高的电压是根本原因;补丁预计将于8月中旬推出【更新】

英特尔终于宣布了解决CPU崩溃和不稳定性问题的方法&#xff0c;声称过高的电压是根本原因&#xff1b;补丁预计将于8月中旬推出【更新】 英特尔官方宣布&#xff0c;已找到困扰其CPU的崩溃问题的根本原因&#xff0c;并将于8月中旬前发布微码更新以解决这一问题&#xff0c;从而…

聊聊 C# 中的顶级语句

前言 在 C# 9.0 版本之前&#xff0c;即使只编写一行输出 “Hello world” 的 C# 代码&#xff0c;也需要创建一个 C# 类&#xff0c;并且需要为这个 C# 类添加 Main 方法&#xff0c;才能在 Main 方法中编写代码。从 C# 9.0 开始&#xff0c;C# 增加了 “顶级语句” 语法&…

获取对象碎片情况

查看oracle数据库表上碎片 先创建个函数 FUNCTION get_space_usage1(owner IN VARCHAR2,object_name IN VARCHAR2,segment_type IN VARCHAR2,partition_name IN VARCHAR2 DEFAULT NULL) RETURN sys.DBMS_DEBUG_VC2COLL PIPELINEDASufbl NUMBER;ufby NUMBER;fs1bl NUMBER…

赋值运算符重载和运算符重载

1.运算符重载 在C中&#xff0c;运算符重载是一种强大的特性&#xff0c;它允许我们为已有的运算符赋予新的意义&#xff0c;以便它们能够应用于自定义类型上。 这一特性极大地增强了C的表达能力&#xff0c;使得自定义类型的使用更加直观和自然。例如&#xff0c;如果我们定义…

【区块链+绿色低碳】包头林草市域碳中和体系建设项目 | FISCO BCOS应用案例

在双碳体系建设背景下&#xff0c;政府、企业都在积极探索碳中和价值实现路径。但是在林业碳汇场景中&#xff0c;存在着林权认证、 身份授权、多方机构协作、数据交换等流程&#xff0c;在这些复杂的业务协作中存在一些风险&#xff0c;如&#xff1a;身份信息泄漏、数据造假、…

BSV区块链技术现实应用原理解析

BSV区块链以其卓越的可扩展性、坚如磐石的安全性、极低的交易成本等特性&#xff0c;成为满足企业当下需求并为企业未来成功奠基铺路的理想技术。 BSV协会近期发布了一个题为《驾驭数字化转型&#xff1a;在自动化世界中建立信任——区块链在数据保护和交易优化中的角色》的报…

Java代码基础算法练习-竞猜卡片值-2024.07.22

任务描述&#xff1a; 小米和小王玩竞猜游戏&#xff1a;准备7张卡片包含数字2、3、4、5、6、7、8&#xff0c;从中抽出2张&#xff08;有 顺序之分&#xff0c;抽2、3跟抽3、2是两种情况&#xff09;&#xff0c;猜2张卡片的和&#xff0c;如果是奇数&#xff0c;则猜对。小米…

mmpretrain报错解决记录-socket.gaierror: [Errno -2] Name or service not known

在使用Beit模型时出现 mmengine - INFO - load model from: https://download.openmmlab.com/mmselfsup/1.x/target_generator_ckpt/dalle_encoder.pth 07/19 11:27:30 - mmengine - INFO - Loads checkpoint by http backend from path: https://download.openmmlab.com/mmsel…

unity2022 il2cpp 源码编译

新建一个XCODE静态库工程 从unity安装目录中找到il2cpp源码 Editor\Data\il2cpp\ 改名 il2cpp/libil2cpp -> il2cpp/il2cpp 加入工程中 ->工程根目录 extends/zlib libil2cpp/ buildSettings 相关设置 IOS Deployment Target ios 12.0 Header Search Paths $(in…

总结——TI_音频信号分析仪

一、简介 设备&#xff1a;MSPM0G3507 库&#xff1a;CMSIS-DSP TI 数据分析&#xff1a;FFT 软件&#xff1a;CCS CLion MATLAB 目的&#xff1a;对音频信号进行采样&#xff08;滤波偏置处理&#xff09;&#xff0c;通过FFT获取信号的频率成分&am…

7.23模拟赛总结 [数据结构优化dp] + [神奇建图]

目录 复盘题解T2T4 复盘 浅复盘下吧… 7:40 开题 看 T1 &#xff0c;起初以为和以前某道题有点像&#xff0c;子序列划分&#xff0c;注意到状态数很少&#xff0c;搜出来所有状态然后 dp&#xff0c;然后发现这个 T1 和那个毛关系没有 浏览了一下&#xff0c;感觉 T2 题面…

前端(1)HTML

1、标签 创建1.html文件&#xff0c;浏览器输入E:/frontheima/1.html&#xff0c;可以访问页面 页面展示 在VSCODE安装IDEA的快捷键&#xff0c;比如ctld复制一行、ctrlx剪切 <p id"p1" title"标题1">Hello,world!</p> <p id"p2"…

Java | Leetcode Java题解之第268题丢失的数字

题目&#xff1a; 题解&#xff1a; class Solution {public int missingNumber(int[] nums) {int n nums.length;int total n * (n 1) / 2;int arrSum 0;for (int i 0; i < n; i) {arrSum nums[i];}return total - arrSum;} }

[排序]hoare快速排序

今天我们继续来讲排序部分&#xff0c;顾名思义&#xff0c;快速排序是一种特别高效的排序方法&#xff0c;在C语言中qsort函数&#xff0c;底层便是用快排所实现的&#xff0c;快排适用于各个项目中&#xff0c;特别的实用&#xff0c;下面我们就由浅入深的全面刨析快速排序。…