当前位置: 首页 > news >正文

Any 的原理以及实现

序言

 在 C++17 的更新中引入了一个特别有意思的类型,它提供了一种通用的方式来存储任何类型的数据而不需要提前指定类型, 该类型就是 any
any 允许你将任意类型的数据存储在一个容器中,并且能够在运行时动态地访问该数据。话不多说,让我们一睹为快吧😊!

 首先大家需要注意 anyC++17更新的内容,如果大家需要使用,那么至少 17 及以上的版本!


Any 的使用

 在刚开始使用 any 时,我总认为他是一个万能类型,但是之后,我更认为它是一种容器,能存储任何类型的值。先简单使用一下吧:

int main()
{std::any A = 1;std::any B = std::string("ABC");	A = B;return 0;
}

可以看到 any 不仅可以接受任意类型,还可以进行不同类型的转化。为什么我说 any 更像是一种容器呢?

 首先,一个标准库实现的类型,通常都是会重载流插入流提取,但是 any 不能直接使用:
在这里插入图片描述

那我就是想要打印 any 存储的值该怎么办呢?std::any_cast 提供了类型安全的访问方法(不正确的类型访问抛出异常):
在这里插入图片描述

其次 any 实现的方法也很像一个容器的操作:

// 查看 any 是否存储了值
A.has_value();// 清空 any 的值
A.reset();

 总之,封装到 std::any 中的对象可以是任何类型的对象,只要它是有效的 C++ 类型(例如内置类型、用户自定义类型、类对象等)。


Any 的原理和实现

计算机的世界没有魔法。 any 是怎么实现的类型擦除的呢?大家可能第一时间想到模板。确实,模板帮助了我们进行泛型编程。但是,只是模板肯定是不行的,模板在编译时就确定了一个容器存储的类型,但是我们在执行代码时可以看到:

std::any A = 1;
std::any B = std::string("ABC");	A = B;

在运行时,这里 A 的存储的类型可是从 int -> string,这可不是模板能够做到的。这里还使用到了 多态

抽象基类

std::any 的核心是一个抽象基类 holder,它定义了存储对象的接口,例如复制和销毁等。所有实际存储对象的类都会继承自这个基类,并实现其接口:

class holder {
public:virtual ~holder() = default;  // 析构函数,确保正确释放内存virtual holder* clone() const = 0;  // 用于复制virtual void* data() = 0;  // 用于访问存储的值virtual const std::type_info& type() = 0; // 存储的值的类型
};

关于多态我们觉得使用水果的例子总是很贴切:我们的抽象基类就像是水果一样,他并没有实体,只是一个概念。但是我们的香蕉,苹果,橘子等就是实打实的水果继承了水果的特性…


模板派生类

 派生类不能是特定的类型,而是使用了模板,代表可以接受任意类型:

template <typename T>
class placeholder : public holder {
public:placeholder(const T& value) : _value(value){}placeholder* clone() override {return new placeholder(_value);}void* data() override {return &_value;}const std::type_info& type(){return typeid(_value);}private:T _value;
};

在这里:

  • _value: 存储了实际的数据。
  • clone(): 返回一个新的 placeholder 对象,以支持复制。
  • data(): 返回存储对象的地址,供 any 获取实际的数据。

现在前置任务已经达成了,就差实现 any 了。

any 类实现

 首先该类的成员变量应该是什么呢?我们需要使用 placeholder 接受需要存储的数据,那么成员变量就是 placeholder 咯。肯定不行涩,如果这样,那么我们的类型就固定了,没有达到类型擦除的效果。所以我们需要使用到 holder

private:std::unique_ptr<holder> _holder; // 使用智能指针便于内存管理

构造和析构

 之后就需要考虑构造函数和析构函数了:

 Any() = default; // 无参的template <class T> // 这里需要模板函数接受任意类型Any(const T& val): _val(std::make_unique<placeholder<T>>(val)) // 别忘了传递类型,placeholder 是一个模板类{}~Any() = default;  // 智能指针管理内存,方便了很多
拷贝构造

 现在基本的框架已经搭好了,准备拓展功能了,先实现拷贝构造和运算符重载吧,在这里我们就直接使用到了 clone 函数,再次构造一个对象然后交给智能指针管理:

Any(const Any& other): _holder(other._holder->clone())
{}
赋值运算符重载

 赋值运算符重载直接使用只拷贝传递一个参数,然后将参数的成员变量的值和我们的交换:

Any& operator=(Any other)
{if (&other != this){std::swap(other._holder, _holder);return *this;}
}

这样的操作好处有两个:

  • 我们原来存储的值交给局部变量后,局部变量销毁,自动释放我们原来的值
  • std::swap 会高效地交换两个 _holder,避免了不必要的对象复制
返回保存的值

 现在我们最后需要完成返回我们 any 存储的值,这里就要用上我们实现的返回类型了:

template <class T >T& any_cast() {// 判断返回的类型是否合法if (typeid(T) == _holder->type()){return *static_cast<T*>(_holder->data()); // static_cast 更为安全的类型转换}else{throw std::bad_cast();}}

any 虽然实现了类型擦除,但是他背后的开销还是不小的,所以在对于高性能需求的场景,可以考虑是否需要 any 这样的通用类型。


总结

 在这篇文章中,我们介绍了 any 的使用,以及具体的实现。any 的实现离不开多态的思想,通过多态,才能够动态地存储不同类型的数据,而不需要在编译时确定数据的具体类型。

相关文章:

Any 的原理以及实现

序言 在 C17 的更新中引入了一个特别有意思的类型&#xff0c;它提供了一种通用的方式来存储任何类型的数据而不需要提前指定类型&#xff0c; 该类型就是 any。  any 允许你将任意类型的数据存储在一个容器中&#xff0c;并且能够在运行时动态地访问该数据。话不多说&#xf…...

SQLI LABS | Less-35 GET-Bypass Add Slashes (we dont need them) Integer Based

关注这个靶场的其它相关笔记&#xff1a;SQLI LABS —— 靶场笔记合集-CSDN博客 0x01&#xff1a;过关流程 输入下面的链接进入靶场&#xff08;如果你的地址和我不一样&#xff0c;按照你本地的环境来&#xff09;&#xff1a; http://localhost/sqli-labs/Less-35/ 话不多说…...

RNN(循环神经网络)详解

1️⃣ RNN介绍 前馈神经网络&#xff08;CNN&#xff0c;全连接网络&#xff09;的流程是前向传播、反向传播和参数更新&#xff0c;存在以下不足&#xff1a; 无法处理时序数据&#xff1a;时序数据长度一般不固定&#xff0c;而前馈神经网络要求输入和输出的维度是固定的&a…...

【AI抠图整合包及教程】探索SAM 2:图像与视频分割领域的革新者

在人工智能的浩瀚星空中&#xff0c;Meta公司的Segment Anything Model 2&#xff08;SAM 2&#xff09;犹如一颗璀璨的新星&#xff0c;以其前所未有的图像与视频分割能力&#xff0c;照亮了计算机视觉领域的新航道。SAM 2不仅继承了其前身SAM在零样本分割领域的卓越表现&…...

DevExpress中文教程 - 如何使用AI模型检查HTML编辑中的语法?

DevExpress .NET MAUI多平台应用UI组件库提供了用于Android和iOS移动开发的高性能UI组件&#xff0c;该组件库包括数据网格、图表、调度程序、数据编辑器、CollectionView和选项卡组件等。 目前许多开发人员正在寻找多种方法将AI添加到解决方案中&#xff08;这通常比想象的要…...

python包管理工具pip和conda的使用对比

python包管理工具pip和conda的使用对比 总述1. pip使用2. conda注意虚拟环境之间的嵌套&#xff0c;这个会导致安装包后看不到包&#xff0c;实际是安装到了base环境里 未完待续 总述 pip相对于conda,对应包的依赖关系管理不强&#xff0c;坏处是容易造成包冲突&#xff0c;好…...

Linux案例:DNS服务器配置

Linux案例&#xff1a;DNS服务器配置 实验一&#xff1a;正向解析 服务端配置&#xff1a; [rootserver ~]# setenforce 0 [rootserver ~]# nmcli c modify ens160 ipv4.method manual ipv4.addresses 192.168.70.131/24 ipv4.gateway 192.168.70.2 ipv4.dns 114.114.114.11…...

【Python】__getitem__()方法

getitem() 方法介绍 __getitem__ 方法是 Python 中的一个特殊方法&#xff08;也被称为魔术方法或特殊方法&#xff09;&#xff0c;用于在类中实现索引访问对象元素的操作。这个方法允许对象实现类似于列表、字典等容器类型的索引操作。当自定义类中定义了 __getitem__ 方法时…...

《Atomic Picnic》进不去游戏解决方法

Atomic Picnic有时候会遇到进不去游戏的情况&#xff0c;这可能是由多种原因造成的&#xff0c;玩家可以采取很多解决方法&#xff0c;比如检查电脑配置、更新系统和驱动或验证游戏文件。 Atomic Picnic进不去游戏怎么办 检查电脑配置 查看自己的电脑配置是否达到了游戏的要求…...

学习日志007--python函数 学完再练习练

函数小练习 一、函数的概念 1.定义 函数是组织好的&#xff0c;可重复使用的&#xff0c;用来实现单一&#xff0c;或相关联功能的代码段。 2.作用 函数能提高应用的模块性&#xff0c;和代码的重复利用率 3.定义 函数代码块以 def 关键词开头&#xff0c;后接函数标识符…...

DOM操作和事件监听综合练习——轮播图

下面制作一个如下图所示的轮播图&#xff08;按Enter键可以控制轮播的开启和关闭&#xff0c;或者点击按钮“第几张”即可跳转到第几张&#xff09;&#xff1a; 下面是其HTML和CSS代码&#xff08;还没有设置轮播&#xff09;&#xff1a; <!DOCTYPE html> <html …...

nodejs:下载,安装,系统环境配置,更换镜像

​​​​ 下载 地址&#xff1a;https://nodejs.org/zh-cn/download/prebuilt-installer 安装包 开始安装 安装完成 配置环境变量 将原来的用户变量-> Path D:\nodejs\node_global 【系统变量】 添加Path–>变量名&#xff1a;NODE_PATH-> 变量值&#xff1a;D: \…...

【Django】视图函数

【Django】视图函数 视图函数的本质是Python中的函数&#xff0c;视图函数负责处理用户的请求并返回响应&#xff0c;该响应可以是网页的HTML内容、重定向、404错误、XML文档、图像或者任何东西&#xff0c;一般在应用中的views.py编写&#xff0c;示例代码如下&#xff1a; …...

MySQL查询-补充

数据准备&#xff1a; -- 部门表 create table dept(deptno int primary key, -- 部门编号 主键&#xff1a;唯一&#xff0c;非空dname varchar(14), -- 部门名称loc varchar(13) -- 部门地址 );insert into dept values (10,accounting,n…...

【Python Tips】多个条件判断——一种更加简洁清晰的写法

一、引言 在python写条件判断 if 语句时&#xff0c;有时会遇到多种条件的真假判断考虑&#xff0c;比如要同时考虑A和B两个变量的True or False&#xff0c;只有当两者都为真&#xff0c;或都为假&#xff0c;或任意为真为假&#xff0c;再继续处理。此时如果用 if&#xff0c…...

【Vue】简易博客项目跟做

项目框架搭建 1.使用vue create快速搭建vue项目 2.使用VC Code打开新生成的项目 端口号简单配置 修改vue.config.js文件&#xff0c;内容修改如下 所需库安装 npm install vue-resource --save --no-fund npm install vue-router3 --save --no-fund npm install axios --save …...

【HarmonyOS】PixelMap转化为Uri

【HarmonyOS】PixelMap转化为Uri 问题背景 鸿蒙中的PixelMap类型&#xff0c;其实类似于Android和IOS中的bitmap&#xff0c;是对图片数据信息进行描述的一种逻辑运算使用的图片类型。 而鸿蒙中的Uri类型&#xff0c;本质其实是带file头的文件存储地址&#xff0c;是用来指向…...

【架构论文-2】架构设计中存在的问题和改进方向

一、性能优化相关 当前情况 在高负载情况下&#xff0c;系统的响应时间出现了一定程度的延迟。特别是在业务高峰期&#xff0c;大量并发请求导致部分关键业务模块的处理效率降低&#xff0c;影响了用户体验。改进方向 计划引入性能分析工具对系统进行全面的性能剖析&#xff0…...

go语言中的结构体含义和用法详解

在Go语言中,结构体(struct)是一种聚合数据类型,可以将多个不同类型的数据组合成一个更复杂的类型。结构体类似于面向对象编程中的“类”,但是Go语言没有类和继承的概念,而是通过结构体和接口实现面向对象编程的特性。 1. 结构体的定义 结构体是一组字段(field)的集合…...

985研一学习日记 - 2024.11.8

一个人内耗&#xff0c;说明他活在过去&#xff1b;一个人焦虑&#xff0c;说明他活在未来。只有当一个人平静时&#xff0c;他才活在现在。 日常 1、起床 2、健身 3、LeetCode刷了2题 买卖股票的最佳时机 将最大利润拆分为每天的利润之和&#xff0c;仅仅收集每天的正利润…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...