学习虚幻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" ]
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据-168 Elasticsearch 单机云服务器部署运行 详细流程

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

基于stm32的4G模块点灯实验

led模块功能封装 #include "led.h" #include "sys.h"//初始化GPIO函数 void led_init(void) {GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOB_CLK_ENABLE();//调用GPIO初始化函数gpio_initstruct.Pin GPIO_PIN_8 | GPIO_PIN_9;gpio_inits…

Linux基本指令一眼看懂(简洁表示)

首先先声明是简单表示&#xff0c;如果要全指令有链接 1. ls 指令 ls [选项] [文件/目录]常用选项: -l: 以长格式列出文件和目录的详细信息。 -a: 显示所有文件&#xff0c;包括隐藏文件&#xff08;以.开头的文件&#xff09;。 -h: 以人类可读的格式显示文件大小。 示例: …

基于stm32的esp8266的WIFI控制风扇实验

实验案例&#xff37;&#xff29;&#xff26;&#xff29;控制风扇 项目需求 电脑通过esp8266模块远程遥控风扇。 项目框图 ​ 风扇模块封装 #include "sys.h" #include "fan.h"void fan_init(void) {GPIO_InitTypeDef gpio_initstruct;//打开时钟…

数据库知识点整理

DDL DDL-数据库操作 show databases ------------ 查看所有数据库 select database(); ----------查看当前数据库 create database 数据库名&#xff1b;---- 创建数据库 use 数据库名&#xff1b; --------------使用数据库 drop database 数据库名&#xff1b;--…

day02_计算机常识丶第一个程序丶注释丶关键字丶标识符

计算机常识 计算机如何存储数据 计算机世界中只有二进制。那么在计算机中存储和运算的所有数据都要转为二进制。包括数字、字符、图片、声音、视频等。 进制 进制也就是进位计数制&#xff0c;是人为定义的带进位的计数方法 实例&#xff1a; // 在java 中 可以使用不同…

[PHP]Undefined index错误只针对数组

1、示例一 <?php $a null; var_dump($a[name]); 结果&#xff1a;无报错 2、示例二 <?php $a []; var_dump($a[name]);结果&#xff1a;报错

【JavaEE初阶】深入理解网络编程—使用UDP协议API实现回显服务器

前言 &#x1f31f;&#x1f31f;本期讲解关于TCP/UDP协议的原理理解~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不…

JMeter 中两大高级线程组的区别与应用

一、JMeter 中的高级线程组概述 最近群里的测试小伙伴在问在 JMeter 中&#xff0c;“jpgc - Ultimate Thread Group”和“jpgc - Stepping Thread Group 阶梯加压”有哪些区别和实际应用场景有哪些&#xff1f;所以这里也跟大家分享一下 JMeter 作为一款强大的性能测试工具&a…

Java项目-基于Springboot的应急救援物资管理系统项目(源码+说明).zip

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

基于SpringBoot网上超市的设计与实现(论文+源码)_kaic

摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管理就很关键。因此超市商品销售信…

100 种下划线 / 覆盖层动画 | 终极 CSS(层叠样式表)集合

还在为你的菜单项和链接寻找动画效果而感到疲惫吗&#xff1f; 不用再找了&#xff01;这里列出了 100 多种不同的动画。从简单的到更复杂的&#xff0c;你肯定能找到自己想要的。 无需 SVG&#xff08;可缩放矢量图形&#xff09;&#xff0c;无需 JavaScript&#xff08;脚…

小白也能剪出优秀视频:四大视频剪辑工具推荐!

无论是社交媒体上的短视频分享&#xff0c;还是专业制作的长视频内容&#xff0c;视频剪辑工具都扮演着至关重要的角色。今天&#xff0c;就让我们来探讨几款市面上流行的视频剪辑工具。 福昕视频剪辑 直达链接&#xff1a;www.pdf365.cn/foxit-clip/ 操作教程&#xff1a;立…

使用Diffutoon把视频转换成动漫风格,无需部署,开箱即用

无论是图片动漫转换以及视频动漫转换&#xff0c;我们前期也介绍过相关的模型&#xff0c;但是其模型输出的动漫视频不是有瑕疵&#xff0c;就是动漫效果不唯美&#xff0c;今天介绍一个modelscope社区开源的动漫风格转换模型Diffutoon。 Diffutoon模型接受视频作为输入&#x…

【C语言】循环中断break

在循环使用过程中&#xff0c;可能遇到某些情况需要终止循环。比如按座位查找一位学生&#xff0c;循环查找&#xff0c;找到时可以直接停止。后续的循环将不再执行。 break;只跳出一层循环 例子中的素数判断&#xff0c;查找到根号n停止&#xff1a;一个合数等于两个数的乘积…

新手必须掌握的Linux命令

1.1 常用系统工作命令 echo [linuxprobelocalhost /]$ echo $SHELL /bin/bash 使用$变量的方式提取SHELL的值&#xff0c;并输出到到屏幕上 date [linuxprobelocalhost /]$ date -s "20170901 8:30:00" 将系统时间设置为 reboot ----系统重启命令poweroff --…

JavaWeb Servlet--09深入:注册系统05---动态搜索栏

动态搜索栏 分析&#xff1a;在显示用户信息的表单里有一个下拉框选择用户的信息&#xff0c;一个文本框进行输入&#xff0c;一个按钮就行搜索&#xff0c;在下拉框选择了性别或许姓名的某一个包含字就会返回所有满足的用户。在controller层进行接收选择的搜索条件&#xff0…

Starrocks部署前期准备

前提条件 硬件要求 CPU StarRocks 依靠 AVX2 指令集充分发挥其矢量化能力。因此&#xff0c;在生产环境中&#xff0c;强烈建议您将 StarRocks 部署于 x86 架构 CPU 的服务器上。 您可以在终端中运行以下命令来检查 CPU 是否支持 AVX2 指令集&#xff1a; cat /proc/cpuin…

【深度学习】RNN的简单实现

目录 1.RNNCell 2.RNN 3.RNN_Embedding 1.RNNCell import torchinput_size 4 hidden_size 4 batch_size 1idx2char [e, h, l, o] x_data [1, 0, 2, 2, 3] # 输入&#xff1a;hello y_data [3, 1, 2, 3, 2] # 期待&#xff1a;ohlol# 独热向量 one_hot_lookup [[1, …

如何使用Python合并Excel文件中的多个Sheet

在日常工作中&#xff0c;我们经常会遇到需要处理多个Excel工作表&#xff08;Sheet&#xff09;的情况。比如&#xff0c;一个Excel文件中包含了一个月内每天的数据&#xff0c;每个工作表代表一天。有时候&#xff0c;为了方便分析&#xff0c;我们需要将这些分散的数据合并到…