为什么使用UE4提供的容器类?

如果你用过C++的STL库,你就知道STL提供了各种各样的容器/数据结构,使得你对处理很多数据的时候非常快捷高效。UE4同样也提供了类似的库,库里面的类型是以T开头的,使用UE4提供的容器库可以更好地实现跨平台。所以在UE4进行开发的时候我们很少去使用STL容器,更多时候是使用UE4提供的容器。

一、TArray<T>是什么

如果你学过C++的模板,你就知道TArray<T>是一个模板类型,T是由我们指定的任意类型。比如你想创建一个数组元素都是int类型的动态数组,那么这个数组类型就是TArray<int>,类似的,你可以创建TArray<double>、TArray<FString>等等,T甚至是可以是你自己创建的C++类。

TArray<T>中所有数据元素都是T类型的,因此不能混合各种不同类型的元素进去这个容器。TArray没有设计成被继承的,所以不应该去继承它。并且new/delete一个TArray是危险的行为。当TArray的生命周期结束时(超出作用域),容器里面的所有元素也会被销毁。当你从另一个TArray创建一个新的TArray会复制所有数据元素到新的变量,而不会共享这些元素的内存。

二、创建动态数组

为了创建一个动态数组,你可以这样写:

TArray<int32> IntArray;

注意,int32是32位整形,而int会根据机器不同而字节不同,所以为了跨平台建议使用int32。

这时候,因为我们没有数据填充到该数组里面,所以还没有内存被分配。

三、填充动态数组

1) TArray::Init

在UE4的官方文档可以看到该函数的声明:

void Init(const ElementType & Element, int32 Number)

该函数用于设置数组为Number个,并且每个元素值的为Element,例如:

IntArray.Init(, );// IntArray == [10,10,10,10,10]

2) TArray::Add

先来看该函数的声明:

int32 Add( const ElementType & Item)

该函数用于添加新元素到动态数组末尾。

3) TArray::Emplace

先来看该函数的声明:

template<typename... ArgsType>int32 Emplace( ArgsType &&... Args)

该函数也是用于添加新元素到动态数组末尾。示例:

TArray<FString> StrArr;StrArr.Add(TEXT("Hello"));StrArr.Emplace(TEXT("World"));// StrArr == ["Hello","World"]

虽然Add和Emplace都是添加新元素到动态数组末尾,不过它们的内部实现是不同的:

  • Add会复制元素到数组容器里面
  • Emplace使用你给的参数来构造一个新的元素类型的实例

在上面的示例中,Add创建了一个FString临时变量,然后传递给数组,在数组内部再次调用拷贝构造函数来复制这个FString临时变量。但是Emplace使用了C++11的右值引用技术,它不会构造临时变量,而是在数组内部使用这个字符串常量来创建FString变量。因此,由于Emplace少了一次拷贝构造函数操作,所以Emplace会比FString高效。但是由于Add比Emplace更具可读性,如果是普通的C++内置类型(不会有拷贝构造函数的巨大开销),建议使用Add。

4) TArray::Push

TArray::Push提供了两个一样功能的重载函数可以分别代替Add和Emplace。所以无论何时使用Push比Add和Emplace更加方便了:

void Push( const ElementType & Item )void Push( ElementType && Item )

四、迭代动态数组

通常迭代都至少有两种方式,一种是使用索引,一种是使用迭代器。

1) 使用索引迭代动态数组

为了练习我们的数组,我们可以在靠近NPC的函数中打印该数组。我们将ANPC::Prox_Implementation修改成如下代码:

void ANPC::Prox_Implementation(
AActor* otherActor,
UPrimitiveComponent* otherComp,
int32 otherBodyIndex,
bool bFromSweep,
const FHitResult & sweepResult
) {
//通过强制转换成AAVatar是否成功来判断是否玩家角色
if (Cast<AAvatar>(otherActor) == nullptr)
{
return;
}
//获得第一人称控制器
APlayerController* PController = GetWorld()->GetFirstPlayerController();
if (PController)
{
//获得HUD界面
AMyHUD* hud = Cast<AMyHUD>(PController->GetHUD());
hud->AddMessage(Message(NpcMessage, .f, FColor::White));
//测试数组
TArray<int> array;
array.Push();
array.Push();
array.Push();
for (int index = ; index < array.Num(); index++)
{
//GEngine是全局引擎变量,我们使用它的AddOnScreenDebugMessage函数来在游戏屏幕上打印调试信息。
//该函数第一个参数是调试输出的位置,填写-1表示总在原来的调试信息上方。
//第二个参数是字体大小,第三个参数是字体颜色,第四个参数是要打印的字符串,这里用FromInt函数将Int转换FString。
GEngine->AddOnScreenDebugMessage(-, , FColor::White, FString::FromInt(array[index]));
}
}
}

注意,每次调试打印的信息都在原来的调试信息上面,所以数组里面的内容依次是1、3、7,而不是7、3、1。

2) 使用迭代器循环数组

void ANPC::Prox_Implementation(
AActor* otherActor,
UPrimitiveComponent* otherComp,
int32 otherBodyIndex,
bool bFromSweep,
const FHitResult & sweepResult
) {
//通过强制转换成AAVatar是否成功来判断是否玩家角色
if (Cast<AAvatar>(otherActor) == nullptr) {
return;
}
//获得第一人称控制器
APlayerController* PController = GetWorld()->GetFirstPlayerController();
if (PController)
{
//获得HUD界面
AMyHUD* hud = Cast<AMyHUD>(PController->GetHUD());
hud->AddMessage(Message(NpcMessage, .f, FColor::White));
//测试数组
TArray<int> array;
array.Push();
array.Push();
array.Push();
//在使用容器的时候,为了容器的操作一致性,通常都会像下面这样使用迭代器来循环
//所谓的迭代器其实类似于一个指针,当对指针进行++时,就指向后面的元素。
//当超出容器范围的时候,迭代器为空,跳出循环
for (TArray<int>::TIterator it = array.CreateIterator(); it; ++it)
{
//GEngine是全局引擎变量,我们使用它的AddOnScreenDebugMessage函数来在游戏屏幕上打印调试信息。
//该函数第一个参数是调试输出的位置,填写-1就不会覆盖以前的调试信息。
//第二个参数是字体大小,第三个参数是字体颜色,第四个参数是要打印的字符串,这里用FromInt函数将Int转换FString。
GEngine->AddOnScreenDebugMessage(-, , FColor::White, FString::FromInt(*it));
}
}
}

在实际开发中,因为使用迭代器进行迭代更简洁美观,我们通常都会这样进行迭代容器。

找到一个元素是否在 TArray
寻找UE4容器是容易的。它通常使用find成员函数完成。使用前面创建的数组,我们可以通过键入以下代码行来找到值10的索引:
int index = array.Find( 10 ); // would be index 3 in image above

[UE4]动态数组:TArray容器的更多相关文章

  1. Delphi泛型动态数组的扩展--转贴

    此文章转载于http://www.raysoftware.cn/?p=278&tdsourcetag=s_pcqq_aiomsg的博客 从Delphi支持泛型的第一天起就有了一种新的动态数组类 ...

  2. STL之顺序容器 deque 动态数组

    deque是一个动态数组,deque与vector非常类似,vector是一个单向开口的连续线性空间,deque则是双向开口的连续线性空间.两者唯一的区别是deque可以在数组的开头和末尾插入和删除数 ...

  3. 容器(vector)、数组、new创建的动态数组,你到底用哪一个(执行效率分析)

    1.问题的提出 在没有了解vector之前,动态数组一般都是又new创建的.在了解vector后发现vector竟是那样方便好用,但方便的同时却是以牺牲执行效率为代价的.网上对vector和array ...

  4. [UE4]C 语言动态数组

    在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定.对于这种问题,用静态数组的办法很难解决.为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数结合指 ...

  5. [UE4]集合:TSet容器

    一.TSet<T>是什么 UE4中,除了TArray动态数组外,还提供了各种各样的模板容器.这一节,我们就介绍集合容器——TSet<T>.类似于TArray<T>, ...

  6. 常用数据结构-线性表及Java 动态数组 深究

    [Java心得总结六]Java容器中——Collection在前面自己总结的一篇博文中对Collection的框架结构做了整理,这里深究一下Java中list的实现方式 1.动态数组 In compu ...

  7. 线性表之顺序存储结构(C语言动态数组实现)

    线性表的定义:N个数据元素的有限序列 线性表从存储结构上分为:顺序存储结构(数组)和 链式存储结构(链表) 顺序存储结构:是用一段连续的内存空间存储表中的数据 L=(a1,a2,a3....an) 链 ...

  8. 菜鸟nginx源代码剖析数据结构篇(一)动态数组ngx_array_t

    菜鸟nginx源代码剖析数据结构篇(一)动态数组ngx_array_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csd ...

  9. QVector&lt;QString&gt; 显示器里面的动态数组元素QString和char *转变

    QVector类是一类提供了动态数组模板. QVector<T>是Qt普通容器类的一种. 它将自己的每个对象存储在连续的内存中.能够使用索引號来高速訪问它们.QList<T>. ...

随机推荐

  1. 获取bean的两种方式

    BeanFactory方式: 1: public void testFactory(){ ResourcePatternResolver rpt=new PathMatchingResourcePat ...

  2. mybatis之sql执行有数据但返回结果为null

    最近在使用mybatis查询数据库时,发现在pl/sql中单独执行sql时结果是有值的,但是在程序中拿到的却是null,相关配置如下: (1) <resultMap type="mon ...

  3. php变量和字符串连接符——点

    连接符——点,本身也是一种运算符.它真正的名字应该叫“字符运算符”.作用是把两个字符串连接起来. echo 字符 . 变量 . 字符;  //点号把三个值连接成为一个,运行正常. 例: 1.字符串+变 ...

  4. windows运行打开服务命令

    1. gpedit.msc-----组策略    2. sndrec32-------录音机   3. Nslookup-------IP地址侦测器   4. explorer-------打开资源管 ...

  5. Oracle Statistic 统计信息 小结

    oraclestatisticstabledatabasesqldictionary   目录(?)[-] 直方图上列的信息说明 直方图类型说明   一.  Statistic 说明 Oracle 官 ...

  6. ZOJ 3432 Find the Lost Sock (异或的运用)

    Alice bought a lot of pairs of socks yesterday. But when she went home, she found that she has lost ...

  7. with() {} 的用法

    var use = "other"; var katana = { isSharp: true, use: function(){ this.isSharp = !!this.is ...

  8. 在 Roslyn 分析语法树时添加条件编译符号的支持

    我们在代码中会写 #if DEBUG 或者 [Conditional("DEBUG")] 来使用已经定义好的条件编译符号.而定义条件编译符号可以在代码中使用 #define WAL ...

  9. 《DSP using MATLAB》Problem 3.5

    定义为: 如果序列绝对可和,其DTFT就存在.

  10. JS常用功能

    1.字符串转Json var json='[{"id":0,"text":"ddddd"},{"id":1," ...