【UEC++学习-UE容器之TArray】


TArray

TArray:负责同类型对象(元素)序列的所有权和组织权。

一、创建数组

// 创建数组
TArray<int32> IntArray;
InArray.Init(10, 5);	//InArray = [10, 10, 10, 10, 10]

二、填充数组

1、Add()Emplace:末尾添加元素

Add()Emplace()方法向数组末尾添加元素

  • Add()添加时创建临时变量,复制到数组中
  • Emplace()不创建临时变量,在容器内 “原地构造” 元素
// Add 和 Emplace
TArray<FString> StrArr;
StrArr.Add    (TEXT("Hello"));
StrArr.Emplace(TEXT("World"));	// StrArr == ["Hello","World"]

2、Append():添加其他TArray中的多个元素

TArray<FString> StrArr = {TEXT("Hello"), TEXT("World")};
TArray<FString> NewStrArr = {TEXT("Unreal"), TEXT("Engine")};
StrArr.Append(NewStrArr);	// StrArr = ["Hello", "World", "Unreal", "Engine"]

3、Insert():插入元素

Insert()给定索引处添加元素

StrArr.Insert(TEXT("Brave"), 1); // StrArr = ["Hello", "Brave", "World", "Unreal", "Engine"]

4、SetNum():设置数组数量

SetNum()设置数组元素的数量

  • 如新数量大于当前数量,则使用元素类型的默认构造函数新建元素;
  • 如新数量小于当前数量,SetNum 将移除元素。
StrArr.SetNum(8);		// StrArr = [Hello, Brave, World, Unreal, Engine, , , ]
StrArr.SetNum(3);		// StrArr = [Hello, Brave, World]

三、迭代

TArray<int32> Arr = {1, 2, 3}
// auto 范围遍历
for (auto& i : Arr)
{
    i = ...;
}
// 基于索引迭代
for (int32 i = 0; i < Arr.Nums(); ++i)
{
    Arr[i] = ...;
}
// 迭代器迭代
for (auto Iter = Arr.CreateIterator(); Iter; ++Iter)	// CreateConstIterator 只读迭代器
{
    *Iter = ...;
}

四、排序

Sort()方法可对数组排序

StrArr.Sort();	// 按元素的 运算符< 进行排序
// StrArr = ["Brave", "Engine", "Hello", "Unreal", "World"]
auto SortFunc = [](const FString& A, const FString& B)
{
    return A.Len() > B.Len();
};
StrArr.Sort(SortFunc);	// 按自定义排序规则排序
// StrArr = ["Engine", "Unreal", "Brave", "Hello", "World"] 同长度元素内部顺序可能不同
StrArr.StableSort(SortFunc)	// 稳定排序
// StrArr = ["Engine", "Unreal", "Brave", "Hello", "World"]

五、查询

1、Num():查询数组数量

Num()查询TArray元素个数

int32 ArrLength = StrArr.Num();	// ArrLength = 5

2、GetData():获取数组指针

GetData()获取TArray指针;如容器为常量,则返回的指针也为常量。

FString* StrPtr = StrArr.GetData();	// 返回数组指针 StrPtr[0] = StrArr[0] = Engine

运算符[]获取指定索引位置元素,会返回引用,可修改容器中的元素;如容器为常量,返回常量引用。

3、Last()Top():获取最后元素

Last()从数组末端反向索引,索引默认为零。Top()方法同Last(),区别是不接受索引

FString Elem1 = StrArr[1];		    // Elem1 = "Unreal"
StrArr[3] = StrArr[3].ToUpper();	// StrArr = ["Engine", "Unreal", "Brave", "HELLO", "World"]

FString ElemEnd = StrArr.Last();	// ElemEnd = "World"
FString ElemEnd1 = StrArr.Last(1);	// ElemEnd1 = "HELLO"
FString ElemTop = StrArr.Top();		// ElemTop = "World"

4、Contains()Find():是否存在特定元素

Contains()查询数组是否包含指定元素

bool bHello = StrArr.Contains(TEXT("Hello"));		// bHello   == true
bool bGoodBye = StrArr.Contains(TEXT("GoodBye"));	// bGoodbye == false

Find()查找元素是否存在,并返回其找到的首个元素的索引;FindLast()会返回其找到的最后一个元素的索引;

如果不将索引作为显式参数传递,这两个函数会将元素索引作为返回值返回;如未找到元素,将返回特殊 INDEX_NONE 值:

int32 Index;
StrArr.Add(TEXT("HELLO"));
bool bFind = StrArr.Find(TEXT("HELLO"), Index);		// bFind = true, Index = 3
bFind = StrArr.FindLast(TEXT("HELLO"), Index);		// bFind = true, Index = 5
Index = StrArr.Find(TEXT("HELLO"));				   // Index = 3;

六、移除

1、Remove():移除全部特定元素

Remove()移除根据元素类型的运算符==移除所有与提供元素相等的元素

TArray<int32> IntArr = {10, 20, 30, 5, 10, 15, 20, 25, 30};
IntArr.Remove(20);			// IntArr = [10, 30, 5, 10, 15, 25, 30]

2、RemoveSingle():移除首个特定元素

IntArr.RemoveSingle(30);	// IntArr = [10, 5, 10, 15, 25, 30]

3、RemoveAt():移除索引位置上元素

IntArr.RemoveAt(2);			// IntArr = [10, 5, 15, 25, 30]

4、RomoveAll():移除满足条件的所有元素

IntArr.RemoveAll([](int32 val)
{
    return val % 3 == 0;
});						   // IntArr = [10, 5, 25]

上述方法移动过程存在开销。如不需要剩余元素排序,可使用 RemoveSwapRemoveAtSwapRemoveAllSwap 函数减少此开销。此类方法其不保证剩余元素的排序,因此可更快地完成任务

5、Empty():移除所有元素

七、运算符

1、赋值运算符=

赋值运算符=可以为数组进行赋值,可以理解为一次深拷贝

IntArr = {1, 2, 3};
TArray<int32> NewIntArr = IntArr;
NewIntArr[0] = 5;
// IntArr = [1, 2, 3]
// NewIntArr = [5, 2, 3]

2、运算符+=

运算符+=等同于Append()方法

NewIntArr += IntArr;			// NewIntArr = [5, 2, 3, 1, 2, 3]

3、MoveTemp

TArray支持移动语义MoveTemp,移动后,源数组为空

IntArr = MoveTemp(NewIntArr);	
// IntArr = [5, 2, 3, 1, 2, 3]
// NewIntArr = []

4、==!=

运算符==!=可用于比较TArray,只有元素的排序和数量相同时,两个数组中元素通过自身类型的运算符==相比

八、堆

1、数组转换为堆

TArray有支持二叉堆数据结构的函数,Heapify()方法可将数组转换为堆,方法支持接受谓词,无谓词默认使用元素类型的运算符<来确定排序

TArray<int32> HeapArr = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
HeapArr.Heapify();			// HeapArr = [1, 2, 4, 3, 6, 5, 8, 10, 7, 9]

2、HeapPush():添加新元素到堆

HeapPush()可将新元素添加到堆,并对其他节点重新排序

HeapArr.HeapPush(4);		// HeapArr = [1, 2, 4, 3, 4, 5, 8, 10, 7, 9, 6]

3、HeapPop()HeapPopDiscard():移除堆顶节点

HeapPop()HeapPopDiscard()用于移除堆的顶部节点,前者引用元素类型返回顶部元素,后者只移除。移除后会对其他节点重新排序

int32 TopNode;			    // TopNode = 1
HeapArr.HeapPop(TopNode);	 // HeapArr = [2, 3, 4, 6, 4, 5, 8, 10, 7, 9]

4、移除给定索引元素

HeapRemoveAt()删除数组中给定索引处的元素,并对其他节点重新排序

HeapArr.HeapRemoveAt(1);	// HeapArr = [2, 4, 4, 6, 9, 5, 8, 10, 7]

5、HeapTop():获取顶部节点,无需变更数组

TopNode = HeapArr.HeapTop(); // TopNode = 2	

九、Slack(空闲容量)

Slack理解为容器中已分配内存但未被用到的那些元素存储槽,默认构建的数组不分配内存,Slack初始为零。

1、GetSlack():获取当前Slack量

GetSlack()可以获取当前数组的Slack量,Max()可以获取当前容器最大分配元素量,Num()即为两者之差。

TArray<int32> SlackArray;
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 0
// SlackArray.Max()      == 0
SlackArray.Add(1);
// SlackArray.GetSlack() == 3
// SlackArray.Num()      == 1
// SlackArray.Max()      == 4
SlackArray.Add(2);
SlackArray.Add(3);
SlackArray.Add(4);
SlackArray.Add(5);
// SlackArray.GetSlack() == 17
// SlackArray.Num()      == 5
// SlackArray.Max()      == 22

2、Reserve():分配内存

Reserve 可分配内存,无需添加元素,如果分配的内存比当前小,则无效。

SlackArr.Reserve(25);	// Num:5, Max:25, Slack:20
SlackArr.Reserve(1);	// Num:5, Max:25, Slack:20

3、Empty()Reset():清空数组(重新分配内存)

Empty()Reset()方法清空容器为容器重新分配内存,区别是Reset()方法分配时不会释放先前的内存。

SlackArr.Empty(10);	// Num:0, Max:10, Slack:10
SlackArr.Reset(10);	// Num:0, Max:22, Slack:22

4、Shrink():移除所有Slack,不影响数组中元素

SlackArr = {1, 2, 3, 4};	// Num:4, Max:22, Slack:18
SlackArr.Shrink();		    // Num:4, Max:4, Slack:0

十、其他

1、Swap()交换元素值

SlackArr.Swap(1, 3);		// SlackArr = [1, 4, 3, 2]

2、GetAllocatedSize():数组内存占用量

GetAllocatedSize()估算当前数组内存占用量,数组类型Sizeof()的值 × 数组的Max()

SIZE_T CountBytes = MyArr.GetAllocatedSize();	// 16

文章作者: Woilin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Woilin !
评论
  目录