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

学习虚幻C++开发日志——TSet

TSet

官方文档:虚幻引擎中的Set容器 | 虚幻引擎 5.5 文档 | Epic Developer Community (epicgames.com)

TSet 是通过对元素求值的可覆盖函数,使用数据值本身作为键,而不是将数据值与独立的键相关联。

默认情况下,TSet 不支持重复的键,但使用模板参数可激活此行为。

TSet 是一种快速容器类,用于在排序不重要的情况下存储唯一元素。TSet 可以非常快速地添加、查找和删除元素(恒定时间)。在大多数情况下,只需要一种参数——元素类型。但是,TSet 可配置各种模板参数来改变其行为,使其更全面。除了可指定从 DefaultKeyFuncs 的派生结构体来提供散列功能,还可允许集合中的多个键拥有相同的值。它和其它容器类一样,可设置自定义内存分配器来存储数据。

和 TArray 一样,TSet 是同质容器。TSet 也是值类型,支持常规复制、赋值和析构函数操作,以及其元素较强的所有权。TSet 被销毁时,其元素也将被销毁。键类型也必须是值类型。

TSet 使用散列,即如果给出了 KeyFuncs 模板参数,该参数会告知集合如何从某个元素确定键,如何比较两个键是否相等,如何对键进行散列,以及是否允许重复键。它们默认只返回对键的引用,使用 运算符== 对比相等性,使用非成员函数 GetTypeHash 进行散列。默认情况下,集合中不允许有重复的键。如果您的键类型支持这些函数,则可以将其用作集合键,无需提供自定义 KeyFuncs。要写入自定义 KeyFuncs,可扩展 DefaultKeyFuncs 结构体。

最后,TSet 可通过任选分配器控制内存分配行为。标准虚幻引擎4(UE4)分配器(如 FHeapAllocator 和 TInlineAllocator)不能用作 TSet 的分配器。实际上,TSet 使用集合分配器,该分配器可定义集合中使用的散列桶数量以及用于存储元素的标准UE4分配器。

与 TArray 不同的是,内存中 TSet 元素的相对排序既不可靠也不稳定,对这些元素进行迭代很可能会使它们返回的顺序和它们添加的顺序有所不同。这些元素也不太可能在内存中连续排列。集合中的后台数据结构是稀疏数组(在数组中有空位。从集合中移除元素时,稀疏数组中会出现空位)。将新的元素添加到阵列可填补这些空位。

但是,即便 TSet 不会打乱元素来填补空位,指向集元素的指针仍然可能失效,因为如果存储器被填满,又添加了新的元素,整个存储可能会重新分配。

1.创建和填充集合

创建一个MapActor类并继承于Actor,其与TArray创建方法一样就不一一详细介绍;

Actor类头文件增添代码:

public:UFUNCTION(BlueprintCallable)void InitSet();

源文件增添代码:

void ASetActor::InitSet()
{TSet<FString> FruitSet;//此处的元素按插入顺序排列,但不保证这些元素在内存中实际保留此排序。//如果是新集合,可能会保留插入排序,但插入和删除的次数越多,新元素不出现在末尾的可能性越大。FruitSet.Add(TEXT("Banana"));FruitSet.Add(TEXT("Grapefruit"));FruitSet.Add(TEXT("Pineapple"));// FruitSet == [ "Banana", "Grapefruit", "Pineapple" ]FruitSet.Add(TEXT("Pear"));FruitSet.Add(TEXT("Banana"));//此处与上面的键重复因此覆盖了,但此处会触发扩容// FruitSet == [ "Banana", "Grapefruit", "Pineapple", "Pear" ]// Note:Only one banana entry.//此处,参数直接传递给键类型的构造函数。这可以避免为该值创建临时 FString。//与 TArray 不同的是,只能使用单一参数构造函数将元素放到集合中。FruitSet.Emplace(TEXT("Orange"));//追加元素,用Emplace函数代替Add避免插入集合时创造临时文件// FruitSet == [ "Banana", "Grapefruit", "Pineapple", "Pear", "Orange" ]TSet<FString> FruitSet2;FruitSet2.Emplace(TEXT("Kiwi"));FruitSet2.Emplace(TEXT("Melon"));FruitSet2.Emplace(TEXT("Mango"));FruitSet2.Emplace(TEXT("Orange"));FruitSet.Append(FruitSet2);// FruitSet == [ "Banana", "Grapefruit", "Pineapple", "Pear", "Orange", "Kiwi", "Melon", "Mango" ]
}

注意元素以及Num的变化,从而去理解TSet键的原理 (使用数据值本身作为键)

2.编辑UPROPERTY TSet

如果用 UPROPERTY 宏和一个可编辑的关键词(EditAnywhereEditDefaultsOnly 或 EditInstanceOnly)标记 TSet,则可在虚幻编辑器中添加和编辑元素。

Actor类头文件增添代码:

public:UPROPERTY(BlueprintReadWrite,EditAnyWhere,Category = SetExample)TSet<FString> MyFruitSet;

在蓝图可编辑操作

此处为FString,但其也可以放结构体

3.迭代

Actor类头文件增添代码:

public:UFUNCTION(BlueprintCallable)void LoopSet();

源文件增添代码:

void ASetActor::LoopSet()
{TSet<FString> FruitSet;FruitSet.Add(TEXT("Banana"));FruitSet.Add(TEXT("Grapefruit"));FruitSet.Add(TEXT("Pineapple"));//依次输出元素for (auto& Elem :FruitSet)//此处的auto可换为FString,其本质时自动推导类型{FPlatformMisc::LocalPrint(*FString::Printf(TEXT(" \"%s\"\n"),*Elem));}//创建迭代器(如为CreateConstIterators 函数则为常量迭代器)for (auto It = FruitSet.CreateIterator(); It; ++It){//注意后面*(*It),第一个*是把FString类型变成TCHAR,第二个是指针,因为迭代器It是地址FPlatformMisc::LocalPrint(*FString::Printf(TEXT("(%s)\n"),*(*It)));}for (auto It = FruitSet.CreateConstIterator(); It; ++It){FPlatformMisc::LocalPrint(*FString::Printf(TEXT("(%s)\n"),*(*It)));}
}

4.查询

Actor类头文件增添代码:

public:UFUNCTION(BlueprintCallable)void QuerySet();

源文件增添代码:

void ASetActor::QuerySet()
{TSet<FString> FruitSet;bool bHave=false;FruitSet.Add(TEXT("Banana"),&bHave);//此处bHave为falseFruitSet.Add(TEXT("Grapefruit"));FruitSet.Add(TEXT("Pineapple"));FruitSet.Add(TEXT("Banana"),&bHave);//此处使得bHave为trueint32 Count = FruitSet.Num();// Count == 3//要确定集合是否包含特定元素,可按如下所示调用 Contains 函数bool bHasBanana = FruitSet.Contains(TEXT("Banana"));bool bHasLemon = FruitSet.Contains(TEXT("Lemon"));// bHasBanana == true// bHasLemon == false//使用 FSetElementId 结构体可查找集合中某个键的索引。FSetElementId SetElementId=Fruit.Add(TEXT("Water"));//FSetElementId为标识符,此处SetElementId={Index=3}FruitSet[SetElementId]+=TEXT("Modify");//此处将Index为3的元素进行修改为"WaterModify"//使用 Find 函数查找一次即可完成这些行为。//如果集合中包含该键,Find 将返回指向元素数值的指针。如果映射不包含该键,则返回null。对常量集合调用Find,返回的指针也将为常量。FString* PtrBanana = FruitSet.Find(TEXT("Banana"));FString* PtrLemon = FruitSet.Find(TEXT("Lemon"));// *PtrBanana == "Banana"//  PtrLemon == nullptr//Array 函数会返回一个 TArray,其中填充(覆盖,即使有元素在内)了 TSet 中每个元素的一份副本。因此元素的生成数量将始终等于集合中的元素数量TArray<FString> FruitArray = FruitSet.Array();//用Array函数转换为TArray数组
}

 5.移除

Actor类头文件增添代码:

public:UFUNCTION(BlueprintCallable)void RemoveSet();

源文件增添代码:

void ASetActor::RemoveSet()
{TSet<FString> FruitSet;FruitSet.Reserve(4);FruitSet.Add(TEXT("Banana"));FruitSet.Add(TEXT("Grapefruit"));FruitSet.Add(TEXT("Pineapple"));FruitSet.Add(TEXT("GG"));FruitSet.Add(TEXT("HH"));FruitSet.Add(TEXT("JJ"));//Remove函数有两种使用参数方法FruitSet.Remove(FSetElementId::FromInterger(0));//通过索引移除第一个元素//Remove函数会返回已删除元素的数量。int32 GGNum=FruitSet.remove(TEXT("GG"));//GGNum=1int32 MMNum=FruitSet.remove(TEXT("MM"));//MMNum=0TSet<FString> FruitSet1=FruitSet;FruitSet1.Reset();//将集合中的所有元素移除,但内存空间还在TSet<FString> FruitSet2=FruitSet;FruitSet2.Empty(0);//此操作是将元素及其内存空间都删除
}

6.排序&运算符&Slack

6.1排序

TSet 可以排序。排序后,迭代集合会以排序的顺序显示元素,但下次修改集合时,排序可能会发生变化。由于排序不稳定,可能按任何顺序显示集合中支持重复键的等效元素。

Actor类头文件增添代码:

public:UFUNCTION(BlueprintCallable)void SortSet();

源文件增添代码:

void ASetActor::SortSet()
{TSet<FString>FruitSet={ "Orange","Pear", "Melon", "Grapefruit", "Mango", "Kiwi"};FruitSet.Sort([](const FString& A, const FString& B) {return A > B; // sort by reverse-alphabetical order});// FruitSet == [ "Pear", "Orange", "Melon", "Mango", "Kiwi", "Grapefruit" ] (order is temporarily guaranteed)//Sort 函数使用指定排序顺序的二进制谓词FruitSet.Sort([](const FString& A, const FString& B) {return A.Len() < B.Len(); // sort strings by length, shortest to longest});// FruitSet == [ "Pear", "Kiwi", "Melon", "Mango", "Orange", "Grapefruit" ] (order is temporarily guaranteed)
}

6.2运算符

其和 TArray 一样,TSet 是常规值类型,可通过标准复制构造函数赋值运算符进行复制。因为集合严格拥有其元素,复制集合的操作是深层的,所以新集合将拥有其自身的元素副本。

Actor类头文件增添代码:

public:UFUNCTION(BlueprintCallable)void OpeatorSet();

源文件增添代码:

void ASetActor::SortSet()
{TSet<FString>FruitSet={ "Orange","Pear", "Melon", "Grapefruit", "Mango", "Kiwi"};TSet<FString> NewSet = FruitSet;//在新的进行增删改查NewSet.Add(TEXT("Apple"));NewSet.Remove(TEXT("Pear"));
}
//在移除目录处也有提及

6.3Slack 

其用法与TMap容器大致相似

Actor类头文件增添代码:

public:UFUNCTION(BlueprintCallable)void SlackSet();

源文件增添代码:

void ASetActor::SortSet()
{TSet<FString>FruitSet={ "Orange","Pear", "Melon", "Grapefruit", "Mango", "Kiwi"};//Reset函数可在不取消任何内存的情况下移除集合中的所有元素,从而产生slackFruitSet.Reset();FruitSet.Reserve(10);//在原基础上追加预分配10个内存for (int32 i = 0; i < 10; ++i){FruitSet.Add(FString::Printf(TEXT("Fruit%d"), i));}
// FruitSet == [ "Fruit9", "Fruit8", "Fruit7" ..."Fruit2", "Fruit1", "Fruit0" ]// Remove every other element from the set.for (int32 i = 0; i < 10; i += 2){FruitSet.Remove(FSetElementId::FromInteger(i));}
// FruitSet == ["Fruit8", <invalid>, "Fruit6", <invalid>, "Fruit4", <invalid>, "Fruit2", <invalid>, "Fruit0", <invalid> ]//Shrink裁剪元素FruitSet.Shrink();//注意此处数组Max值为10 
// FruitSet == ["Fruit8", <invalid>, "Fruit6", <invalid>, "Fruit4", <invalid>, "Fruit2", <invalid>, "Fruit0" ]//CompactStable函数压缩元素,Compact函数则可能改变排序FruitSet.CompactStable();// FruitSet == ["Fruit8", "Fruit6", "Fruit4", "Fruit2", "Fruit0", <invalid>, <invalid>, <invalid>, <invalid> ]FruitSet.Shrink();// FruitSet == ["Fruit8", "Fruit6", "Fruit4", "Fruit2", "Fruit0" ]
}

 

相关文章:

学习虚幻C++开发日志——TSet

TSet 官方文档&#xff1a;虚幻引擎中的Set容器 | 虚幻引擎 5.5 文档 | Epic Developer Community (epicgames.com) TSet 是通过对元素求值的可覆盖函数&#xff0c;使用数据值本身作为键&#xff0c;而不是将数据值与独立的键相关联。 默认情况下&#xff0c;TSet 不支持重…...

面向对象进阶(下)(JAVA笔记第二十二期)

p.s.这是萌新自己自学总结的笔记&#xff0c;如果想学习得更透彻的话还是请去看大佬的讲解 目录 抽象方法和抽象类抽象方法定义格式抽象类定义格式抽象方法和抽象类注意事项 接口接口的定义接口中成员变量的特点接口中没有构造方法接口中成员方法的特点在接口中定义具有方法体…...

通信协议——UART

目录 基础概念串行&并行串行的优缺点 单工&双工 UART基本概念时序图思考&#xff1a;接收方如何确定01和0011 基础概念 串行&并行 串行为8车道&#xff0c;并行为1车道 串行的优缺点 通行速度快浪费资源布线复杂线与线之间存在干扰 单工&双工 单工&#xf…...

最优阵列处理技术(七)-谱加权

阵列的加权技术等价于时间序列谱分析中的加窗或锐化技术。在加权过程中,需要考虑的是如何降低旁瓣并使主波束宽度的增长最小。 首先需要明确的是,在 u u u空间下的波束方向图为 B u ( u ) =...

Java | Leetcode Java题解之第486题预测赢家

题目&#xff1a; 题解&#xff1a; class Solution {public boolean PredictTheWinner(int[] nums) {int length nums.length;int[] dp new int[length];for (int i 0; i < length; i) {dp[i] nums[i];}for (int i length - 2; i > 0; i--) {for (int j i 1; j …...

leetcode动态规划(十五)-完全背包

题目 leetcode上没有纯完全背包题目&#xff0c;可以看卡码网上的题目 完全背包 思路 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品都有无限个&#xff08;也就是可以放入背包多次&#xff09;&#xff…...

AI视听新体验!浙大阿里提出视频到音乐生成模型MuVi:可解决语义对齐和节奏同步问题

MuVi旨在解决视频到音乐生成(V2M)中的语义对齐和节奏同步问题。 MuVi通过专门设计的视觉适配器分析视频内容,以提取上下文 和时间相关的特征,这些特征用于生成与视频的情感、主题及其节奏和节拍相匹配的音乐。MuVi在音频质量和时间同步方面表现优于现有基线方法,并展示了其在风…...

对比两个el-table,差异数据突显标记

前言 在数据分析和数据处理的过程中&#xff0c;经常需要对比两个数据集&#xff0c;以便发现其中的差异和变化。本文将介绍如何使用 el-table 组件来对比两个数据集&#xff0c;并通过差异数据的突显标记&#xff0c;帮助用户更直观地理解数据的变化。 cell-style 属性 其实利…...

调研funasr时间戳返回时间坐标效果可用性

# 背景 : 分析funasr识别结果中每个中文字的时间戳偏差情况 1.评价指标: ①偏差公式: A=标注字的时间戳(帧长区间) B=识别字的时间戳(帧长区间) 偏差=(AB的区间并集-AB的区间交际) 偏差百分比=(AB的区间并集-AB的区间交际)/(A的帧长) def calculate_bias(la…...

Tomcat默认配置整理

Connector: 处理请求的具体配置 Tomcat的连接等待队列长度&#xff0c;默认是100 Tomcat的最大连接数&#xff0c;默认是8192 Tomcat的最小工作线程数&#xff0c;默认是10 Tomcat的最大线程数&#xff0c;默认是200 Tomcat的连接超时时间&#xff0c;默认是20s Server port…...

深入理解Rust中的指针:裸指针 智能指针

Rust是一种注重安全性的系统编程语言&#xff0c;它通过所有权、借用和生命周期等机制来保证内存安全。在Rust中&#xff0c;指针的使用是小心翼翼的&#xff0c;因为指针操作是导致内存错误的主要原因之一。然而&#xff0c;指针在处理底层数据和性能优化时又是必不可少的。本…...

物联网实训项目:绿色家居套件

1、基本介绍 绿色家居通过物联网技术将家中的各种设备连接到一起&#xff0c;提供家电控制、照明控制、电话远程控制、室内外遥控、防盗报警、环境监测、暖通控制、红外转发以及可编程定时控制等多种功能和手段。绿色家居提供全方位的信息交互功能&#xff0c;甚至为各种能源费…...

缓存雪崩是什么

背景 Redis的缓存雪崩是指在某一时间段内&#xff0c;大量缓存数据同时失效&#xff0c;导致大量请求直接打到数据库上&#xff0c;造成数据库压力激增&#xff0c;甚至可能导致数据库宕机。这种情况类似于雪崩效应&#xff0c;突然的大量请求涌入数据库&#xff0c;系统无法承…...

【格物刊】龙信刊物已上新

文章关键词&#xff1a;电子数据取证、电子物证、手机取证、介质取证 深藏注册表的秘密&#xff1a;一次揭开金融阴谋的成功取证 一场看似无懈可击的金融操作&#xff0c;背后是否隐藏着阴谋&#xff1f;执法部门接到举报&#xff0c;指控几名金融机构的高层管理人员涉嫌利用…...

DNA存储介绍

1. DNA存储的基本原理 DNA存储技术基于DNA分子的双螺旋结构&#xff0c;利用其四种碱基&#xff08;A、T、C、G&#xff09;来编码信息。每个碱基可以代表一个二进制位&#xff08;bit&#xff09;&#xff0c;其中A和C可以代表0&#xff0c;G和T可以代表1&#xff0c;或者使用…...

如何修改MAC地址破解网络无线网络限制-担心别人蹭网,路由器设置MAC地址过滤,限定了能访问无线网络的网卡地址-供大家学习参考

路由器都设置了MAC地址过滤&#xff0c;也就是限定了能访问无线网络的网卡的MAC地址。因为无线路由器不一定由自己控制&#xff0c;所以当更换了笔记本或者更换了无线网卡的时候&#xff0c;也许就上不了网了。我们可以修改网卡的MAC地址实现上网。 下载&#xff1a;https://do…...

C端产品经理与B端产品经理的区别

一&#xff1a;需求量级不一样 C端是面向消费者&#xff0c;吃的是人口红利&#xff0c;可能与社会大环境关系比较大&#xff0c;C端一般中大厂的需求多 B端是面向公司&#xff0c;吃的是产业红利&#xff0c;B端产品经理无论什么规模的公司都需要。 二&#xff1a;B端产品更…...

书生营 L0G4000 玩转HF/魔搭/魔乐社区

模型下载 在codespace上给环境装包&#xff0c;按照教材即可 运行后下载成功 建立下载json文件 新建下载internlm2_5-chat-1_8b的json文件 运行结果 基本上没啥问题&#xff0c;照着教程来就行 模型上传&#xff08;可选&#xff09; push的时候需要先认证token 最后的…...

轻松检测麦克风功能:使用Python的sounddevice和soundfile库

轻松检测麦克风功能&#xff1a;使用Python的sounddevice和soundfile库 在进行音频处理或开发需要使用麦克风的应用程序时&#xff0c;确保麦克风功能正常是非常重要的。本文将介绍一个简单的Python脚本&#xff0c;它能够帮助我们检测本地麦克风的功能&#xff0c;确保我们的设…...

k8s 部署步骤整理(containerd)

版本&#xff1a;v1.31 容器运行时&#xff1a;containerd 网络插件&#xff1a;flannel 系统&#xff1a;Ubuntu22.04 安装部署步骤 安装containerd sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl …...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...