일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- STCF
- Rr
- dtft
- AINCAA
- 운영체제
- 게임개발
- CTF
- 언리얼엔진
- RBAC
- DP
- Race condition
- dirty cow
- 배경 그림
- MLFQ
- pdlc
- Security
- TSet
- frequency-domain spectrum analysis
- stride
- sampling theory
- ret2libc
- Unity #Indie Game
- Double free
- MAC
- 유니티
- 게임 개발
- 메카님
- linear difference equation
- 유스케이스
- DSP
- Today
- Total
다양한 기록
[UE] Unreal Container Library / TArray, TSet 본문
언리얼 엔진 자체 제작 자료구조 라이브러리
유용하게 쓰는 거: TArray, TMap, TSet
** T는 템플릿을 뜻함
C++ STL은 표준이긴 한데 많은 기능이 있어 컴파일이 오래 걸림
언리얼 컨테이너 라이브러리가 더 가볍고 언리얼 엔진에 최적화됨
vector -> TArray
set - x > TSet
map - x > TMap
용도는 유사한데 셋이랑 맵은 내부 구현이 다름
TArray
- 가변 배열 자료구조
- 데이터가 순차적으로 모여있어서 메모리를 효과적 사용, 캐시 효율이 좋음(공간적 지역성)
- 언제나 그렇듯 이런 자료구조는 중간 삭제하는게 느림
- 많은 수의 데이터에서 검색이 많이 일어나면 TSet이 나음
- 연산: GetData(), Insert(), [] 연산자, Add(), Emplace(), Append(), Remove()
- 두가지 프로퍼티: 엘리먼트 유형 , 얼로케이터
엘리먼트 유형
- 배열에 저장되는 오브젝트 유형
- 유형이 다른 엘리먼트를 하나의 TArray에 저장 불가
얼로케이터
- 기본값1, 보통 그냥 이대로 씀
TArray는 값 유형이다
- 동적 할당을 하지 않는다는 뜻
- 다른 TArray 변수에서 TArray 변수를 만들면 복사되고 공유 안함
.Init(10, 5)
- 10을 기본값으로 5개 만듦
Add()
추가할 데이터를 밖에서 생성해서 TArray에다 복사해서 집어넣음
Emplace()
TArray 자체에서 그냥 생성
사소한 거에는 Add, 외에는 Emplace를 쓰는게 효율적
가독성은 Add가 좋긴 함
Append()
- 여러 값을 한 번에 넣는 경우
AddUnique()
기존에 없는 거면 추가 .. 일반적인 경우엔 차라리 Set쓰는게 나음
Insert(~~~, 2)
주어진 인덱스에 추가 -> 배열 구조가 바뀜
언리얼에서는 Count말고 Num 함수를 써서 배열 크기를 구하는데
SetNum()으로 배열 크기를 인위적으로 바꿀 수 있음
반복처리는 일반 for 문도 되고, for range도 가능
읽기 전용으로 하고 싶으면 const 붙이거나 CreatConstIterator 써서 가능
소팅
일반 Sort()도 있고 HeapSort()도 있음 (둘다 Unstable 함)
StableSort()도 있음 (이건 병합 정렬로 구현됨)
쿼리
Num()으로 엘리먼트 개수 구할 수 있음
GetData()로 배열 내 엘리먼트에 대한 포인터 반환 가능
유효하지 않은 인덱스를 물어보는 경우 .. IsValidIndex()로 체크 가능
operator []는 레퍼런스를 반환함
-> 배열이 const가 아니면 배열 내 엘리먼트 변형하는데 사용 가능
Top(), Last() 는 거꾸로 접근 가능
Contains(~~) 는 배열에 특정 엘리먼트가 있는지 확인 가능
Find(~~, index) 는 인덱스도 반환해줌
엘리먼트를 찾지 못한 경우 INDEX_NONE 반환함
근데 검색을 많이 해야 하면 그냥 Set 쓰는게 나음
Remove(value)는 값 삭제, 데이터 변동 좀 있음, 일치하는 거 다 지움
RemoveSingle(vlaue)는 처음 일치한 것 삭제
RemoveAt(idx)는 인덱스로 제거
RemoveAll(~~~~)로 조건에 일치하는 엘리먼트 전부 제거 가능
ValArr.RemoveAll( [](int32 Val) {
return Val % 3 == 0;
});
이런식으로 이용 가능
** 인덱스 정리되어서 배열에 구멍이 생기는 일은 없음
Empty() -> 배열의 모든 것을 제거
연산자
= : 값을 복사해서 할당
+= : Append 함수처럼 연결 가능
Temp2 = MoveTemp(Temp1) : 값이 아예 이동됨
== : 엘리먼트의 수와 순서까지 같아야 함 * FString이 대소문자는 구분 못함 주의
힙
Heapify 쓰면 배열이 힙으로 바뀜
슬랙
보통 요구한 거보다 메모리를 더 줌
(앞으로 엘리먼트가 추가될 거니까, 메모리 요청 오버헤드 감소 및 외부 단편화 방지 용도인듯 함)
원시 메모리
TArray -> 메모리를 둘러싼 포장 단위, 원시 메모리 접근 API가 존재
.AddUninitailized( size ) : 초기화하지 않고 빠르게 크기만 할당해주는 거
FMemory::Memcpy( dst, src, size ) : 메모리 복사도 지원함
디버그 하려면 DebugGameEditor 모드로 해야 함
아니면 이름 안보여서 검색이 안됨
확인해보면 순서대로 들어가는 거 확인 가능
TSet
STL의 set과의 비교
STL set
- 이진 트리로 구성되어 정렬을 지원
- 메모리 구성이 효율적이지 않고, 요소 삭제 시 균형을 위해 재구축 발생 가능
- 순회에 적합하지 않음
TSet
- 해시 테이블 형태
- 동적 배열이라 데이터가 모여있음, 데이터 삭제해도 재구축 일어나지 않고, 빠르게 순회 가능
- 비어있는 데이터가 있을 수 있음
* STL의 unordered_set과 유사한 동작
TSet은 내부적으로 동적 가변 배열로 구성됨
-> 중간중간 데이터가 빠질 수도 있음
그리고 추가 시 비어있는 부분을 메우는 방식으로 작동
빠진 부분이 있어도 어쨌든 모여있긴 해서 순회도 잘 됨
설명
독립된 키로 값을 연결하는게 아니라 데이터 값 자체를 키로 사용
중복 지원 안하고, 속도가 빠름
TArray처럼 소멸 시 엘리먼트도 같이 소멸됨
세트 생성 및 채우기
TSet<FString> FruitSet;
.Add(~~~);
.Emplace(~~~);
.Append(다른 세트) -> 병합
이터레이션
레인지드 for 사용 가능
CreatConstIterator로 읽기 전용으로 만들기도 가능
쿼리
.Num()
.Contains()
* 내부적으로 해시테이블로 찾은 아이디는 FSetElementId 구조체에 저장
.Find() .. Contains 후 [] 로 찾으면 두 번 조회하는 거라 비효율적이라 하나로 합침, 못찾으면 널
.Array() -> TArray로 반환, 빈틈은 날림
제거, 소팅, 할당 등..
슬랙은 중간에 생길수도 있고, 끝에 생길 수도 있음
.Shrink()는 뒤쪽 슬랙을 제거
커스텀 구조체를 통한 TSet
== 연산자랑 해당 타입에 대한 GetTypeHash() 만들어줘야 함
CountBytes나 GetAllocatedSize로 크기도 알 수 있음
일단 Num이 5라고 나오긴 해도 실제로는 빈칸이 존재
저 밑에 Raw 뷰에 Element에서 제대로 확인이 가능한데, 빈 칸에는 Invalid 들어가 있음
가장 마지막에 빠진 요소 자리부터 빈틈을 채움
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyGameInstance.h"
#include "Algo/Accumulate.h"
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 };
Int32ArrayCompare.AddUninitialized(ArrayNum);
FMemory::Memcpy(Int32ArrayCompare.GetData(), CArray, ArrayNum * sizeof(int32));
ensure(Int32Array == Int32ArrayCompare);
int32 Sum = 0;
for (const auto& num : Int32Array)
{
Sum += num;
}
int32 SumByAlgo = Algo::Accumulate(Int32Array, 0);
ensure(Sum == SumByAlgo);
////////////////////////////////////////////////////////////
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);
}
'언리얼 엔진 > Unreal C++' 카테고리의 다른 글
[UE] Memory Management (0) | 2024.12.29 |
---|---|
[UE] Unreal Container Library / Struct, Map (0) | 2024.12.28 |
[UE] Delegate (델리게이트) / 발행 구독 패턴 (0) | 2024.12.26 |
[UE] Composition (컴포지션) (0) | 2024.12.22 |
[UE] Interface (인터페이스) (0) | 2024.12.22 |