[공부 내용 정리] 11강 언리얼 컨테이너 라이브러리 - 구조체와 Map

2025. 3. 21. 01:13·언리얼 공부/이득우의 언리얼 프로그래밍

0. 강의 내용 요약

  • TArray: 빈틈없는 메모리, 가장 높은 접근 성능, 가장 높은 순회성능
  • TSet: 빠른 중복 감지
  • TMap: 중복 불허, 키 밸류 관리
  • TMultiMap: 중복 허용, 키 밸류 관리
  TArray TSet TMap TMultiMap
접근 O(1) O(1) O(1) O(1)
검색 O(N) O(1) O(1) O(1)
삽입 O(N) O(1) O(1) O(1)
삭제 O(N) O(1) O(1) O(1)

 

더보기

구조체와 언리얼 컨테이너 라이브러리

1. TArray, TSet, TMap 컨테이너 라이브러리 내부 구조와 활용 방법

2. 언리얼 구조체의 선언 방법

3. TSet 과 TMap 에서 언리얼 구조체를 사용하기 위해 필요한 함수의 선언과 구현 방법

 

 


 

 

1. 실습 코드

더보기

1. 헤더 파일

// 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"

USTRUCT() // 언리얼 구조체임을 선언
struct FStudentData 
{
	// 이 경우네는 public 으로 끝나게 됨. 여기서 작성하는 매크로들이 public 으로 끝나기 때문에구조체가 원래 가지고 있는 접근 지시자인 public 그대로 사용
	GENERATED_BODY()

	// 생성자
	FStudentData()
	{
		Name = TEXT("홍길동");
		Order = -1;
	}
	// 인자를 가진 생성자를 만들어서 자유롭게 사용 가능
	// 구조체는 언리얼 오브젝트가 아니기 때문에 newAPI 를 사용해서 생성될 일이 없기 때문!
	FStudentData(FString InName, int32 InOrder) : Name(InName), Order(InOrder) {}

	// 첫번째로 Operate== 를 추가해준다.
	bool operator==(const FStudentData& InOther) const
	{
		return Order == InOther.Order;
	}
	// 두번째로 getTypeHash 에 대한 선언
	// 이것은 전역함수로 선언할수도 있고, 아니면 friend 키워드를 사용해서 안쪽에 선언하면 더 깔끔해짐
	// hash 값은 unit32 로 반환을 해주고 getTypeHash 함수를 만들어주되 인자로는 레퍼런스를 넣어주고
	// 리턴 값에 대해서는 우리가 이미 가지고 있는 인티저 오더에 대한 hash 값을 이거에 대한 해시값으로 리턴을 해주는 것으로 이 student 에 대한 해시값을 지정
	friend FORCEINLINE uint32 GetTypeHash(const FStudentData& InStudentData)
	{
		return GetTypeHash(InStudentData.Order);
	}


	UPROPERTY()
	FString Name;

	UPROPERTY()
	int32 Order;
};

/**
 * 
 */
UCLASS()
class UNREALCONTAINER_API UMyGameInstance : public UGameInstance
{
	GENERATED_BODY()

public:
	virtual void Init() override;

private:
	// 이 경우는 값타입이기 때문에 메모리를 관리할 필요가 없다.
	// 그래서 Reflection 기능으로 뭔가 조회를 하지 않는다면 굳이 UProperty 를 붙일 필요는 없다.
	TArray<FStudentData> StudentsData;

	// TArray 헤더에서 언리얼 오브젝트 헤더에서 언리얼 오브젝트 포인터를 선언할 때는 TObjectPtr 로 감싸줘야 함.
	UPROPERTY() // 이땐느 포인터를 우리가 관리하게 되는데 이렇게 T-Array 에 내부적으로 포인터를 관리하게 되면 반드시 자동으로 언리얼 엔진이 메모리를 관리할 수 있게 U-Property Macro 를 붙여줘야 됨. 필수!!!
	TArray<TObjectPtr<class UStudent>> Students;

	// TMap
	// 키나 밸류에 언리얼 오브젝트 포인터가 들어가면 UPROPERTY 를 반드시 선언해줘야 하는데 없다면 걍 안해줘도 됨
	TMap<int32, FString> StudentsMap;
};

 

 

2. cpp 파일

// Fill out your copyright notice in the Description page of Project Settings.


#include "MyGameInstance.h"
#include "Algo/Accumulate.h" // 합계를 구할 수 있는 Accumulate 함수를 사용할 수 있음

FString MakeRandomName()
{
	TCHAR FirstChar[] = TEXT("김이박최");
	TCHAR MiddleChar[] = TEXT("상혜지성");
	TCHAR LastChar[] = TEXT("수은원연");

	TArray<TCHAR> RandArray;
	RandArray.SetNum(3); // 일단 기본값으로 3개 채워
	RandArray[0] = FirstChar[FMath::RandRange(0, 3)];
	RandArray[1] = MiddleChar[FMath::RandRange(0, 3)];
	RandArray[2] = LastChar[FMath::RandRange(0, 3)];

	// TArray<TCHAR> 는 캐릭터 배열을 그냥 포함하고 있는 컨테이너
	// 이 포인터 값을 우리가 넘겨주면 반환 값을 F-String 으로 지정했기 때문에 자동으로 F-String 이 만들어져서 반환됨.
	return RandArray.GetData();
}

void UMyGameInstance::Init()
{
	Super::Init();

	// 간단한 정수형의 TArray 실습
	const int32 ArrayNum = 10;
	TArray<int32> Int32Array;

	for (int32 ix = 1; ix < ArrayNum; ++ix) {
		Int32Array.Add(ix); // 성능을 정말 신경쓰고 싶다면 Add 말고 emplace 쓰기
	}

	// 조건문에 해당하는 걸 람다함수로 넣는 것이 일반적
	Int32Array.RemoveAll(
		[](int32 Val) {
			// 짝수만 다 제거하도록 람다 함수 넣기..
			return Val % 2 == 0;
		}
	);
	Int32Array += {2, 4, 6, 8, 10}; // 이제 배열의 모습은 1,3,5,7,9,2,4,6,8,10


	// 이번에는 C 스타일처럼 row 하게 바로 메모리에 접근
	TArray<int32> Int32ArrayCompare;
	int32 CArray[]{ 1,3,5,7,9,2,4,6,8,10 };
	Int32ArrayCompare.AddUninitialized(ArrayNum); // Int32ArrayCompare 에 일단 10개 를 넣어줌..
	// 복제
	FMemory::Memcpy(Int32ArrayCompare.GetData(), CArray, sizeof(int32) * ArrayNum);
	// 이제 두개가 같은지 확인
	ensure(Int32Array == Int32ArrayCompare); // 이렇게 했을 때 문제 없으면 같은거임


	// 더해보장!
	int32 Sum = 0;
	for (const int32& Int32Elem : Int32Array) 
	{
		Sum += Int32Elem;
	}
	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);


	// 구조체를 사용해서 300명의 학생을 만들어봥
	// 랜덤하게 이름 생성하는 함수
	const int32 StudentNum = 300;
	for (int32 ix = 1; ix <= StudentNum; ++ix)
	{
		// 구조체로 데이터를 집어넣는 경우에는 아무래도 복사 비용이 조금 발생하기 때문에 Add 보다는 emplace 사용해주는 것이..
		StudentsData.Emplace(FStudentData(MakeRandomName(), ix));
	}

	// StudentsData 를 TArray 로 옮겨보장
	TArray<FString> AllStudentsName;
	Algo::Transform(StudentsData, AllStudentsName,
		[](const FStudentData& Val) {
			return Val.Name;
		}
	);
	UE_LOG(LogTemp, Log, TEXT("모든 학생 이름의 수 : %d"), AllStudentsName.Num());

	// StudentsData 를 TSet 으로 옮겨보장
	// 얘는 중복을 허용하지 않아용
	TSet<FString> AllUniqueNames;
	Algo::Transform(StudentsData, AllUniqueNames,
		[](const FStudentData& Val)
		{
			return Val.Name;
		}
	);
	UE_LOG(LogTemp, Log, TEXT("중복 없는 학생 이름의 수 : %d"), AllUniqueNames.Num());


	// TMap 으로 옮겨보장
	Algo::Transform(StudentsData, StudentsMap,
		[](const FStudentData& Val) {
			return TPair<int32, FString>(Val.Order, Val.Name);
		}
	);
	UE_LOG(LogTemp, Log, TEXT("순번에 따른 학생 맵의 레코드 수 : %d"), StudentsMap.Num());
	
	// 일반 맵의 경우에는 중복을 허용하지 않기 때ㅐ문에 유니크 네임이라고 이름지음
	TMap<FString, int32> StudentsMapByUniqueName;
	Algo::Transform(StudentsData, StudentsMapByUniqueName,
		[](const FStudentData& Val) {
			return TPair<FString, int32>(Val.Name, Val.Order);
		}
	);
	UE_LOG(LogTemp, Log, TEXT("이름에 따른 학생 맵의 레코드 수 : %d"), StudentsMapByUniqueName.Num());

	// 근데 만약 중복을 허용하고 싶어
	TMultiMap<FString, int32> StudentMapByName;
	Algo::Transform(StudentsData, StudentMapByName,
		[](const FStudentData& Val) {
			return TPair<FString, int32>(Val.Name, Val.Order);
		}
	);
	UE_LOG(LogTemp, Log, TEXT("이름에 따른 학생 멀티맵의 레코드 수 : %d"), StudentMapByName.Num());

	// 어떤 이름을 가진 학생이 몇 명있는지 정보 뽑아봦
	const FString TargetName(TEXT("이혜은"));
	TArray<int32> AllOrders;
	StudentMapByName.MultiFind(TargetName, AllOrders);
	UE_LOG(LogTemp, Log, TEXT("이름이 %s인 학생 수 : %d"), *TargetName, AllOrders.Num());


	// TSet 에 FStudentData 자료구조를 선언해본다
	TSet<FStudentData> StudentsSet;
	for (int32 ix = 1; ix <= StudentNum; ++ix)
	{
		// 우리가 지정한 커스텀 구조체에 대한 여기 보이는 것처럼 getTypeHash 함수가 지정되엉 ㅣㅆ지 않아서 hash 값을 만들 수 없다는 에러 메시지 뜸
		// 이것을 위해 FStudentData 에 두가지 함수를, 구조체 두가지 함수를 추가해 보도록 한다.
		StudentsSet.Emplace(FStudentData(MakeRandomName(), ix));
	}
}

 

 

 


 

 

2. 공식문서

언리얼 엔진의 맵 컨테이너 | 언리얼 엔진 5.5 문서 | Epic Developer Community

 

'언리얼 공부/이득우의 언리얼 프로그래밍' 카테고리의 다른 글
  • [공부 내용 정리] 10강 언리얼 컨테이너 라이브러리 I - Array와 Set
  • [공부 내용 정리] 9강 언리얼 C++ 설계 III - 델리게이트
  • [공부 내용 정리] 8강 언리얼 C++ 설계 II - 컴포지션
  • [공부 내용 정리] 7강 언리얼 C++ 설계 I - 인터페이스
dubu0721
dubu0721
dubu0721 님의 블로그 입니다.
  • dubu0721
    dubu0721 님의 블로그
    dubu0721
  • 전체
    오늘
    어제
    • 분류 전체보기 (334)
      • 프로그래밍언어론 정리 (0)
      • 컴퓨터네트워크 정리 (5)
      • 알고리즘&자료구조 공부 (64)
        • it 취업을 위한 알고리즘 문제풀이 입문 강의 (60)
        • 학교 알고리즘 수업 (3)
        • 실전프로젝트I (0)
      • 백준 문제 (193)
        • 이분탐색 (7)
        • 투포인트 (10)
        • 그래프 (7)
        • 그리디 (24)
        • DP (25)
        • BFS (15)
        • MST (7)
        • KMP (4)
        • Dijkstra (3)
        • Disjoints Set (4)
        • Bellman-Ford (2)
        • 시뮬레이션 (3)
        • 백트래킹 (15)
        • 위상정렬 (5)
        • 자료구조 (25)
        • 기하학 (1)
        • 정렬 (11)
        • 구현 (8)
        • 재귀 (8)
        • 수학 (8)
      • 유니티 공부 (11)
        • 레트로의 유니티 게임 프로그래밍 에센스 (11)
        • 유니티 스터디 자료 (0)
        • C# 공부 (0)
      • 유니티 프로젝트 (48)
        • 케이크게임 (13)
        • 점토게임 (35)
      • 언리얼 공부 (10)
        • 이득우의 언리얼 프로그래밍 (10)
      • 진로 (1)
      • 논문 읽기 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    스택
    레트로의 유니티 프로그래밍
    정렬
    언리얼
    재귀
    오블완
    이득우
    큐
    그리디
    C#
    dp
    맵
    이분탐색
    시뮬레이션
    수학
    유니티 공부 정리
    골드메탈
    유니티 프로젝트
    유니티
    그래프
    BFS
    우선순위큐
    백트래킹
    투포인터
    바킹독
    백준
    해시
    티스토리챌린지
    자료구조
    이벤트 트리거
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
dubu0721
[공부 내용 정리] 11강 언리얼 컨테이너 라이브러리 - 구조체와 Map
상단으로

티스토리툴바