Unreal5 Array, Set

이승한·2024년 4월 2일
0

Unreal5

목록 보기
8/11

학습 내용

언리얼에서 제공하는 대표 컨테이너 라이브러리의 동작 원리와 활용 방법을 예제를 통해 살펴보기

언리얼 컨테이너 라이브러리

  • 언리얼 엔진이 자체 제작해 제공하는 자료구조 라이브러리
  • 언리얼 오브젝트를 안정적으로 지원하며 다수 오브젝트 처리에 유용
  • 언리얼 C++ 다양한 자료구조 라이브러리를 직접 만들어 제공
  • 실제 게임 제작에 유용하게 사용되는 라이브러리로 세 가지를 추천

TArray, TMap, TSet

C++STL과 언리얼 컨테이너 라이브러리의 차이점

C++STL

  1. 범용적으로 설계
  2. 표준이기에 호환성이 높다.
  3. 많은 기능이 엮여 있어 컴파일 시간이 오래 걸린다.

언리얼 컨테이너 라이브러리

  1. 언리얼 엔진에 특화
  2. 언리얼 오브젝트 구조를 안정적으로 지원
  3. 가볍고 게임 제작에 최적화

언리얼 C++주요 컨테이너 라이브러리

  • 두 라이브러리의 이름과 용도는 유사하지만, 내부적으로 다르게 구현되어 있다.
  1. TArray : 오브젝트를 순서대로 담아 효율적으로 관리하는 용도로 사용
  2. TSet : 중복되지 않는 요소로 구성된 집합을 만드는 용도로 사용
  3. TMap : 키,밸류 조합의 레코드를 관리하는 용도로 사용

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 함수 비용 많이 발생

[]연산자(인덱스 오퍼레이터)는 균일한 데이터배열로 되어있기때문에 특정한 인덱스가 주어졌을 때, 해당 인덱스를 빠르게 가져오는 작업이 가능

  • TArray는 값 유형으로 new및 delete로 생성 또는 소멸시키는건 좋지 않다.

  • TArray는 클래스 멤버 변수나 스택에서 소멸을 해주면 된다. 거기 들어있는 엘리먼트의 소멸로 이어진다.

  • 다른 TArray변수에서 TArray 변수를 만들면 그 엘리먼트를 새 변수에 복사하며, 공유되는 상태는 없다.

언리얼 컨테이너 라이브러리에서는 요소의 수를 가져올 때 , Count 말고 Num함수 사용

  • SetNum : 배열의 크기를 늘렸다가 줄였다가 사용가능


MyGameInstance.h

// 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;
};

MyGameInstance.cpp

// 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의 특징

  • STL의 set과 언리얼 TSet의 비교

  • STL set의 특징

1. STL set은 이진 트리로 구성되어 있어 정렬을 지원

2. STL set은 메모리 구성이 효율적이지 않음

3. STL set은 요소가 삭제될 때 균형을 위한 재구축이 일어날수 있음

4. STL set의 모든 자료를 순회하는데 적합하지 않음

  • 언리얼 TSet 특징

1. TSet은 해시테이블 형태로 키 데이터가 구축되어 있어 빠른 검색이 가능

2. TSet은 동적 배열의 형태로 데이터가 모여있음

3. TSet의 데이터는 빠르게 순회할 수 있음

4. TSet의 데이터는 삭제해도 재구축이 일어나지 않음

5. TSet의 자료에는 비어있는 데이터가 있을 수 있음

  • 따라서 STL set과 언리얼 TSet의 활용 방법은 서로 다르기 때문에 주의할 것.

  • STL의 unordered_set과 유사하게 동작하지만 동일하지 않음

  • TSet은 중복 없는 데이터 집합을 구축하는데 유용하게 사용할 수 있음


    동적 가별배열인데 중간에 빠져있는 데이터가 빠져있는 배열이다.
    데이터를 추가할 때 비어있는곳에 채워지기에 순서가 보장되지 않는다.

TSet 공식문서 요약

  • 순서가 중요하지 않은 상황에서 고유 엘리먼트를 저장하는데 사용하는 고속 컨테이너 클래스

  • 데이터값 자체를 키로 사용하며, 이 때 엘리먼트를 값을 평가하는 오버라이드 가능 함수를 사용

  • TSet은 엘리먼트 추가,검색,제거가 매우 빠르다.

  • TSet은 중복키를 지원하지않지만, 템플릿 파라미터로 사용할 수 있다.

  • 커스텀 구조체를 사용해서 TSet을 만드는 경우 2가지를 구현

  1. operator== ( 이퀄리티 오퍼레이터)
  2. 해당 타입에 대한 GetTypeHash 함수
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

순서가 보장되지않음


시간복잡도

TArrayTSet
접근O(1)O(1)
검색O(N)O(1)
삼입O(N)O(1)
삭제O(N)O(1)

TArray : 빈틈없는 메모리,가장 높은 접근 성능,가장 높은 순회성능
TSet : 빠른 중복 감지

0개의 댓글