학습 내용
언리얼 컨테이너 라이브러리
- 언리얼 엔진이 자체 제작해 제공하는 자료구조 라이브러리
- 언리얼 오브젝트를 안정적으로 지원하며 다수 오브젝트 처리에 유용
- 언리얼 C++ 다양한 자료구조 라이브러리를 직접 만들어 제공
- 실제 게임 제작에 유용하게 사용되는 라이브러리로 세 가지를 추천
TArray, TMap, TSet
vector -> TArray (o) : 동작 원리가 거의 동일하다.
set -> TSet (x) : 비슷하긴 하나 내부적으로 구현이 다르게 되어있다.
map -> TMap (x) : 비슷하긴 하나 내부적으로 구현이 다르게 되어있다.
TArray 개요
TArray는 가변 배열(Dynamic Array) 자료 구조
STL의 vector와 동작 원리가 유사
게임 제작에서는 가변 배열 자료구조를 효과적으로 활용하는 것이 좋다.
1. 데이터가 순차적으로 모여있기 때문에 메모리를 효과적으로 사용할 수 있고 캐시 효율이 높다.
2. 컴퓨터 사양이 좋아지면서, 캐시 지역성(Locality)으로 인한 성능 향상은 굉장히 중요해짐
3. 임의 데이터의 접근이 빠르고, 고속으로 요소를 순회하는 것이 가능
가변 배열의 단점
1. 맨 끝에 데이터를 추가하는 것은 가볍지만,중간에 요소를 추가하거나 삭제하는 작업은 비용이 큼
데이터가 많이질 수록 검색,삭제,수정 작업이 느려지기 때문에, 많은 수의 데이터에서 검색 작업이 빈번하게 일어난다면 TArray대신 TSet을 사용하는 것이 좋다.
맨 앞 데이터의 포인터를 가져올때 GetData
끝에 추가하는 함수 Add, Emplace, Append
1. Add(or Push) : 엘리먼트의 유형의 인스턴스를 배열에 복사하는식 -> 밖에서 생성해서 TArray에 복사하는 식
2. Emplace : 지정한 인수를 사용하여 엘리먼트 유형의 인스턴스를 바로 생성해줌 -> TArray안에 바로 생성하는 식
- Emplace 가 효율적 , Add API가 가독성이 좋다. 반복문에서는 Emplace 사용하자
3. Append : 한번에 다수의 객체를 집어넣을때 사용
4. AddUnique : 기존 컨테이너에 동일한 엘리먼트가 존재하면 검색, 존재하지않는 경우 새 엘리먼트 추가
-> 이것을 사용하는것 보다 Set이 더 유용
중간에 추가나 삭제 Insert,Remove 함수 비용 많이 발생
[]연산자(인덱스 오퍼레이터)는 균일한 데이터배열로 되어있기때문에 특정한 인덱스가 주어졌을 때, 해당 인덱스를 빠르게 가져오는 작업이 가능
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "MyGameInstance.generated.h"
/**
*
*/
UCLASS()
class UNREALCONTAINER_API UMyGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
virtual void Init() override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyGameInstance.h"
#include "Algo/Accumulate.h" // 합계를 구할수 있는 Accumulate 함수 사용가능
void UMyGameInstance::Init()
{
Super::Init();
const int32 ArrayNum = 10;
TArray<int32> Int32Array;
for (int32 ix = 1; ix <= ArrayNum; ++ix)
{
Int32Array.Add(ix);
}
Int32Array.RemoveAll(
[](int32 Val)
{
//람다함수 식
return Val % 2 == 0;
}
);
Int32Array += {2, 4, 6, 8, 10};
TArray<int32> Int32ArrayCompare;
int32 CArray[] = { 1,3,5,7,9,2,4,6,8,10 };
//AddUninitialized : 초기화되지않는 데이터를 빠르게 넣어줌
Int32ArrayCompare.AddUninitialized(ArrayNum);
//메모리를 통해 빠르게 복제
FMemory::Memcpy(Int32ArrayCompare.GetData(), CArray, sizeof(int32) * ArrayNum);
//둘이 같은지 확인
ensure(Int32Array == Int32ArrayCompare);
//이런 구문을 Accumulate로 구현 가능
int32 Sum = 0;
for(const int32& Int32Elem : Int32Array)
{
Sum+= Int32Elem;
}
ensure (Sum ==55);
//위의 구문과 동일한 값
int32 SumByAlgo = Algo::Accumulate(Int32Array, 0);
ensure(Sum == SumByAlgo);
}
TSet의 구조와 활용
TSet<int32> Int32Set;
for (int32 ix = 1; ix <= ArrayNum; ++ix)
{
Int32Set.Add(ix);
}
Int32Set.Remove(2);
Int32Set.Remove(4);
Int32Set.Remove(6);
Int32Set.Remove(8);
Int32Set.Remove(10);
Int32Set.Add(2);
Int32Set.Add(4);
Int32Set.Add(6);
Int32Set.Add(8);
Int32Set.Add(10);
->기존 값: 1,2,3,4,5,6,7,8,9,10
->remove
->Add : 1,10,3,8,5,6,7,4,9,2
순서가 보장되지않음
TArray | TSet | |
---|---|---|
접근 | O(1) | O(1) |
검색 | O(N) | O(1) |
삼입 | O(N) | O(1) |
삭제 | O(N) | O(1) |
TArray : 빈틈없는 메모리,가장 높은 접근 성능,가장 높은 순회성능
TSet : 빠른 중복 감지