这是一篇关于UE中TArray数组的文章
一,TArray 的创建、初始化、赋值
TArray 的创建、初始化、赋值的主要形式如下。其中,列表既可以用作构造函数的参数,也可以用来初始化和赋值。Init() 可以在TArray 在放置若干个相同元素。
TArray<FString> Arr;
//Arr is []
TArray<FString> SecArr({ TEXT("Are"), TEXT("you"), TEXT("OK") });
//SecArr is [Are you OK]
TArray<FString> ThirdArr = { TEXT("Are"), TEXT("you"), TEXT("OK") };
//ThirdArr is [Are you OK]
ThirdArr.Init(TEXT("Hello"), 3);
//ThirdArr is [Hello Hello Hello]
Arr = { TEXT("Hello"), TEXT("World") };
//Arr is [Hello World]
增
AddUninitialized
AddUninitialized增加一个没有构造的元素(可能会扩容),他主要是改变TArray类中一个成员:ArrayNum的数值(只有当加完之后的Num值比ArrayMax值大,才会进行扩容)。使用FMemory::Memcpy函数会将数组数据写入,但是不会改变TArray对象的任何成员,因此一般追加数组数据会先AddUninitialized然后进行FMemory::Memcpy数据写入。否则使用Num函数获取数组长度时,是错误的。
protected:
ElementAllocatorType AllocatorInstance;
SizeType ArrayNum;
SizeType ArrayMax;
FORCEINLINE SizeType AddUninitialized(SizeType Count)
{
const USizeType OldNum = (USizeType)ArrayNum;
const USizeType NewNum = OldNum + (USizeType)Count;
ArrayNum = (SizeType)NewNum;
if ((USizeType)Count > (USizeType)ArrayMax - OldNum)
{
ResizeGrow((SizeType)OldNum);//扩容
}
return OldNum;
}
使用示例:
int32 OldSize = UncompressedDataQueue.AddUninitialized(UncompressedDataSize);
FMemory::Memcpy(UncompressedDataQueue.GetData() + OldSize, UncompressedData.GetData(), UncompressedDataSize);
Append
这个方法有好几个,但都殊途同归
左值引用版:获取数组长度后直接用FMemory::Memcpy在后面追加数据
其中TIsBitwiseConstructible<DestinationElementType, SourceElementType>::Value会返回true或者false,在SourceElementType可以转换成DestinationElementType时会返回true,否则返回false,比如TIsBitwiseConstructible<const int*, int* >::Value == true TIsBitwiseConstructible<int*, const int*>::Value == false,ConstructItems函数主要是用它查看是否需要使用构造函数去创建。
template <typename OtherElementType, typename OtherAllocatorType>
void Append(const TArray<OtherElementType, OtherAllocatorType>& Source)
{
check((void*)this != (void*)&Source);
SizeType SourceCount = Source.Num();
// Do nothing if the source is empty.
if (!SourceCount)
{
return;
}
// Allocate memory for the new elements.
SizeType Pos = AddUninitialized(SourceCount);
ConstructItems<ElementType>(GetData() + Pos, Source.GetData(), SourceCount);
}
template <typename DestinationElementType, typename SourceElementType, typename SizeType>
FORCEINLINE void ConstructItems(void* Dest, const SourceElementType* Source, SizeType Count)
{
if constexpr (TIsBitwiseConstructible<DestinationElementType, SourceElementType>::Value)
{
if (Count)
{
FMemory::Memcpy(Dest, Source, sizeof(SourceElementType) * Count);
}
}
else
{
while (Count)
{
new (Dest) DestinationElementType(*Source);
++(DestinationElementType*&)Dest;
++Source;
--Count;
}
}
}
右值引用版本:使用FMemory::Memmove原数组数据被析构并且将ArrayNum也设为0
template <typename OtherElementType, typename OtherAllocator>
void Append(TArray<OtherElementType, OtherAllocator>&& Source)
{
check((void*)this != (void*)&Source);
SizeType SourceCount = Source.Num();
if (!SourceCount)
{
return;
}
SizeType Pos = AddUninitialized(SourceCount);
RelocateConstructItems<ElementType>(GetData() + Pos, Source.GetData(), SourceCount);
Source.ArrayNum = 0;
}
其他都差不多不过有一个指针版本,是上述AddUninitialized示例的简化版:UncompressedDataQueue.Append(UncompressedData.GetData(), UncompressedDataSize);
void Append(const ElementType* Ptr, SizeType Count)
{
check(Ptr != nullptr || Count == 0);
SizeType Pos = AddUninitialized(Count);
ConstructItems<ElementType>(GetData() + Pos, Ptr, Count);
}