기존의 C++ STL은 범용적이며 호환성이 높지만 컴파일 시간이 많이 소모되어 게임 프로그래밍과의 적합성이 낮다. 이 때문에 언리얼은 자체적인 컨테이너 라이브러리인 UCL을 구현해놓았다. 그 안에는 TArray, TSet, TMap을 포함하고 있다.
- TArray
참고 : https://docs.unrealengine.com/5.3/ko/array-containers-in-unreal-engine/
TArray는 STL의 vector와 동작 원리가 유사한 가변 배열 자료구조이다. 기존 동작 배열의 장단점과 같이 임의의 데이터 접근의 속도는 빠르지만(O(1)) 검색하거나 중간에 요소를 추가/삭제하는 동작의 비용은 크다(O(N)).
- TSet
참고 : https://docs.unrealengine.com/5.3/ko/set-containers-in-unreal-engine/
TSet은 중복되지 않는 데이터를 저장하는 자료구조이다. TSet는 데이터 자체를 Key로 가지는 해시 테이블 형태로 내부적으로 구현되어 있기 때문에 빠른 검색이 가능하다. 또한 데이터를 빠르게 순회하는 것이 가능하고 데이터 삭제 시에도 재구축이 일어나지 않는다. 또한 동적 배열 형태로 데이터가 모여있는데 중간 요소를 삭제하면 그 자리는 압축되지 않고 그대로 빈 공간으로 남아있다.
- TMap
참고 : https://docs.unrealengine.com/5.3/ko/map-containers-in-unreal-engine/
TMap은 Key/Value 한 쌍의 중복되지 않는 데이터를 저장하는 자료구조이다. C++ STL의 map이 이진 트리로 구현된 데 반해, TMap은 Key/Value 구성의 튜플 데이터의 TSet 구조로 구현되어 있다. 그렇기에 대부분의 TSet의 장점을 그대고 가지고 있다. TMultiMap을 사용하면 TMap과 달리 중복된 데이터를 관리할 수 있다.
예제 코드
// 학생 정보를 담은 언리얼 구조체
struct FStudentInfo
{
GENERATED_BODY()
FStudentInfo() : Name(TEXT("Unknown")), Id(-1) {}
FStudentInfo(const FString& InName, const int32 InId) : Name(InName), Id(InId) {}
bool operator== (const FStudentInfo& InOther)
{
return this->Name == InOther.Name;
}
friend uint32 GetTypeHash(const FStudentInfo& InStudentInfo)
{
return FCrc::MemCrc32(&InStudentInfo, sizeof(FStudentInfo));
}
UPROPERTY()
FString Name;
UPROPERTY()
int32 Id;
};
// 학생 정보를 저장하는 TArray
TArray<FStudentInfo> StudentsInfo;
FString MakeRandomName()
{
int32 RandomNum = FMath::RandRange(0, 100);
return TEXT("Student") + FString::FromInt(RandomNum);
}
// 무작위 학생 데이터 300개 생성
const int32 StudentNum = 300;
for (int32 ix = 1; ix <= StudentNum; ++ix)
{
StudentsInfo.Emplace(MakeRandomName(), ix);
}
// 학생 이름을 담은 TSet
TSet<FString> StudentSet;
Algo::Transform(StudentsInfo, StudentSet,
[](const FStudentInfo& Val)
{
return Val.Name;
}
);
UE_LOG(LogTemp, Log, TEXT("Total StudentSet Num : %d"), StudentSet.Num());
// 이름을 Key, id를 Value로 가지는 TMap
TMap<FString, int32> StudentNameMap;
Algo::Transform(StudentsInfo, StudentNameMap,
[](const FStudentInfo& Val)
{
return TPair<FString, int32>(Val.Name, Val.Id);
}
);
UE_LOG(LogTemp, Log, TEXT("Total StudentNameMap Num : %d"), StudentNameMap.Num());
// id를 Key, 이름을 Value로 가지는 TMap
TMap<int32, FString> StudentIdMap;
Algo::Transform(StudentsInfo, StudentIdMap,
[](const FStudentInfo& Val)
{
// TPair라는 언리얼 튜플 데이터로 반환
return TPair<int32, FString>(Val.Id, Val.Name);
}
);
UE_LOG(LogTemp, Log, TEXT("Total StudentIdMap Num : %d"), StudentIdMap.Num());
// 이름을 Key, id를 Value로 가지는 TMultiMap
TMultiMap<FString, int32> StudentNameMultiMap;
Algo::Transform(StudentsInfo, StudentNameMultiMap,
[](const FStudentInfo& Val)
{
return TPair<FString, int32>(Val.Name, Val.Id);
}
);
UE_LOG(LogTemp, Log, TEXT("Total StudentNameMultiMap Num : %d"), StudentNameMultiMap.Num());
// 찾고자 하는 학생의 이름
const FString TargetName(TEXT("Student50"));
TArray<int32> FoundStudent;
// 멀티맵에서 해당 이름을 가진 학생 수 구하기
StudentNameMultiMap.MultiFind(TargetName, FoundStudent);
UE_LOG(LogTemp, Log, TEXT("Total student whose name is %s : %d"), *TargetName, FoundStudent.Num());
실행 결과