๐ ํ์ต ๋ ์ง ์ธ์ฆ(์ฃผ์ ์ ๋ฌด๊ด)
- C++ ์ฝ๋์นดํ
- ์ธ๋ฆฌ์ผ C++ ๋น๋ ํ์ดํ๋ผ์ธ ๋ถ์
- AI Model ์บ๋ฆญํฐ ์ ์ฉ ๋ฐ ๋ก์ง ๊ตฌํ
๋ฆฌํ๋ ์ (Reflection)์ ํ๋ก๊ทธ๋จ์ด ์คํ ์ค(Runtime)์ ์๊ธฐ ์์ ์ ๊ตฌ์กฐ์ ์์ฑ์ ๊ด์ฐฐํ๊ณ ์ ์ดํ ์ ์๋ ๋ฅ๋ ฅ ์ ์๋ฏธํ๋ค.
์ฌ์ค ํด๋น ๋ด์ฉ๋ง ๋ณด๋ ๊ฑด ์ดํดํ๊ธฐ ์ด๋ ค์ฐ๋ฏ๋ก, ์๋ ์์๋ฅผ ํตํด์ ์ ๋ฆฌํด๋ณด๋ ค๊ณ ํ๋ค.
์ฝ๋ ์ ๋ฌธ์ ์๋์ง๋ง, ์๋์ ๊ฐ์ด ํ์ค C++๋ก ๋์ํ๋ ํ๋ก๊ทธ๋จ์ด ์๋ค๊ณ ๊ฐ์ ํ์.
class MyPlayer {
public:
int Health = 100;
};
์ด๋, ๋ฐํ์์์ Health๋ผ๋ ์ด๋ฆ์ ์ฌ์ฉํด์ Health์ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์์๊น?
ํ์ค C++์์๋, ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ก๋ง ๋ฉ๋ชจ๋ฆฌ์ ์ ๊ทผํ๊ธฐ ๋๋ฌธ์ Health๋ผ๋ ์ด๋ฆ์ ํตํด์ ๋ณ๊ฒฝํ๋ ค๊ณ ํ๋ฉด ์ ์ ์๋ค.

์ธ๋ฆฌ์ผ C++์์๋ ํน์ ๋ง์ปค๋ง ๋ฌ์์ฃผ๋ฉด ์ธ๋ฆฌ์ผ์ UHT๊ฐ ์ฝ๋๋ฅผ ํ์ด๋ณด๊ณ , ๋ฉํ ๋ฐ์ดํฐ ์ฌ์ ์ ๋ง๋ค์ด ์ค๋ค.
class MyPlayer : public UObject {
GENERATED_BODY()
public:
UPROPERTY()
int Health = 100;
};
๊ทธ๋์ ๋ฆฌํ๋ ์
์ ๋ฐํ์์์ Health๋ผ๋ ์ด๋ฆ์ ์ฌ์ฉํด์ ์ฃผ์๋ฅผ ๋ฐํํ์ฌ ์ ์ ์๋๋ก ๋ง๋ค์ด์ค๋ค.

์ด๋ฌํ ์ด์ ์ ํ์ฉํด์, ๋ฆฌํ๋ ์ ์ ๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ์ ๊ณตํด์ค๋ค.
ํ์ค C++๊ณผ ๋ฌ๋ฆฌ, ์ธ๋ฆฌ์ผ C++์์๋ ๊ฐ๋น์ง ์ปฌ๋ ์
๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
ํ์ค C++์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ํ ๋น(new)/ํด์ (delete)๋ฅผ ์๋์ผ๋ก ํด์ค์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ฉ๋ชจ๋ฆฌ ๋์(Memory Leak), ๋๊ธ๋ง ํฌ์ธํฐ(Dangling Pointer), ์ด์ค ํด์ (Double-Free)ํ์์ด ๋ํ๋ ์ ์๋ค.
์ค๋งํธ ํฌ์ธํฐ์ ๊ฒฝ์ฐ์ ์ฐจ์ด์ ์ด๋ผ๊ณ ํ๋ค๋ฉด, ์ํ ์ฐธ์กฐ๊ฐ ๊ฑธ๋ฆด ์ผ์ด ์์ง๋ง ๊ฐ์ฒด๋ฅผ ์ฒญ์ํ๋ ํ์ด๋ฐ์ ์ ์ ์๋ค๋ ์ ์ด๋ค.
๊ฐ๋น์ง ์ปฌ๋ ์ ์ ๋์ ์๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ๋ค.
๊ฐ๋น์ง ์ปฌ๋ ์ ์ด ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ญ์ ํ ๋ ์ด๋ค ์ผ์ด ์ผ์ด๋๋ ์ง ๋ค์ ์ฝ๋๋ก ํ์ธํด๋ณด๋ ค๊ณ ํ๋ค.
// TestObject.h
UCLASS()
class ADVANCEDPROJECT_API UTestObject : public UObject
{
GENERATED_BODY()
public:
void InitObject(FString InName);
private:
FString MemoName;
};
// TestObject.cpp
void UTestObject::InitObject(FString InName)
{
MemoName = InName;
}
// MyGCObserver.h
UCLASS()
class ADVANCEDPROJECT_API AMyGCObserver : public AActor
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
UPROPERTY()
class UTestObject* SafeObject;
class UTestObject* DangerObject; // ๋ฆฌํ๋ ์
์์คํ
๋ฏธ๋ฑ๋ก, GC ์ฒ๋ฆฌ ๋์
};
// MyGCObserver.cpp
void AMyGCObserver::BeginPlay()
{
Super::BeginPlay();
SafeObject = NewObject<UTestObject>();
SafeObject->InitObject(TEXT("SafeObject"));
DangerObject = NewObject<UTestObject>();
DangerObject->InitObject(TEXT("DangerObject"));
}
// Called every frame
void AMyGCObserver::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
bool bSafeIf = SafeObject != nullptr;
bool bSafeValid = SafeObject->IsValid();
bool bDangerIf = DangerObject != nullptr;
bool bDangerValid = DangerObject->IsValid();
}
์คํํด๋ณด๋ฉด ์๊ฒ ์ง๋ง, ์ฌ๊ธฐ์ DangerObject๋ GC์ ์ํด์ ๋ฉ๋ชจ๋ฆฌ ์ ๊ฑฐ ๋์์ธ๋ฐ, ์ ๊ฑฐ ๋๋๋ผ๋ bDangerIf์ bDangerValid ๋ชจ๋ true๋ก ์ ์ง๋๋ค.
๊ทธ ์ด์ ๋ ๋ฆฌํ๋ ์ ์์คํ ์ ๋ฑ๋กํ์ง ์์๊ธฐ ๋๋ฌธ์, ๊ฐ๋น์ง ์ปฌ๋ ํฐ๊ฐ DangerObject์ ์กด์ฌ๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฆฌํ๋ ์ ์์คํ ์ ๋ฑ๋ก๋ SafeObject์ ๊ฒฝ์ฐ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํด์ ๋๋ฉด ํด๋น ๊ฐ์ nullptr๋ก ๋ณ๊ฒฝํ์ง๋ง, DangerObject๋ ํด์ ๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ฅผ ๊ณ์ ์ง๋๋ Dangling Pointer ํ์์ ์ด๋ํ๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ nullptr, IsValid()๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ํ๋ฅผ ์ฒดํฌํ๊ณ ์ ๊ทผํ๋ ค๊ณ ํ๋ฉด ํฌ๋์๊ฐ ๋ฐ์ํ๋ค.
IsValid()์ ๋์ฒด์ฌ๋ก๋ IsValidLowLevel()์ ์ฌ์ฉํจ์ผ๋ก์จ, ํด๋น ํฌ์ธํฐ๊ฐ ์ ํจํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์๋์ง ๊น๊ฒ ํ๊ณ ๋ค์ด์ผ ํ๋ค.
void AMyGCObserver::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
bool bSafeIf = SafeObject != nullptr;
bool bSafeValid = SafeObject->IsValidLowLevel();
bool bDangerIf = DangerObject != nullptr;
bool bDangerValid = DangerObject->IsValidLowLevel();
}
ํ์ง๋ง IsValidLowLevel()๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ ํจํ์ง๋ง ์ฒดํฌํ ๋ฟ, ์ฌ์ ํ DangerObject๋ Dangling Pointer ํ์์ ๋ง์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ด ์ค๋ธ์ ํธ๋ฅผ ์ฝํ ์ฐธ์กฐ ์ค๋งํธ ํฌ์ธํฐ(TWeakObjectPtr)๋ก ๋จผ์ ์ ์ธํด์ค์ผ ํ๋ค.
์ด๋ฌ๋ฉด, ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ญ์ ๋๋๋ผ๋ DangerObject ๋ํ nullptr๋ก ์ธํ ์ด ๋๋ค.
TWeakObjectPtr<class UTestObject> DangerObject;
UBT(Unreal Build Tool)์ ํ๋ก์ ํธ์ ์ด๋ค ๋ชจ๋์ด ์๊ณ , ์ด๋ค ํ๋ซํผ(Windows, Android, PS5 ๋ฑ)์ผ๋ก ๋น๋ํ ์ง ๊ฒฐ์ ํ๋ ์ญํ ์ ํ๋ค.
์๋ฃจ์ ์ ์ด์ด๋ณด๋ฉด .Target.cs, .Build.cs ํ์ผ์ด ์๋๋ฐ, ํด๋น ํ์ผ๋ค์ ๋ฐํ์ผ๋ก ์ ์ฒด์ ์ธ ๋น๋ ๊ณํ์ ์ธ์ฐ๋ ๊ฒ UBT์ ์ญํ ์ด๋ค.
UHT(Unreal Header Tool)์ C++์ ์ปดํ์ผ๋ฌ๊ฐ ์ฌ๋ฌ ์ธ๋ฆฌ์ผ ๋งคํฌ๋ก(UPROPERTY(), UFUNCTION() ๋ฑ) ์ดํดํ ์ ์๊ฒ ํ๋ ์ญํ ์ ํ๋ฉฐ ์ฌ๋ฌ ๋ฉํ ๋ฐ์ดํฐ๋ค์ ์๋ํฐ์ ๋ฐ์ํ ์ ์๋๋ก .generated.hํ์ผ์ ์์ฑํด์ค๋ค.
๊ทธ๋์ ์ธ๋ฆฌ์ผ์ ๋น๋ ํ์ดํ๋ผ์ธ์ ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ๋ค.
CDO(Class Default Object)๋ UObject ํด๋์ค๋ง๋ค ํ ๊ฐ์ฉ ์ง๋๋ ๊ธฐ๋ณธ๊ฐ ๋ณด๊ด์์ด๋ค.
ํด๋์ค ๋น 1๊ฐ์ CDO๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, CDO๋ ์์ง์ด ์คํ๋๋ ์์ ์์ ์์ฑ๋๋ค.
CDO๊ฐ ์๋ ํ์ค C++๋ก ์ธ์คํด์ค๋ฅผ 100๊ฐ ์์ฑํ๋ค๊ณ ํ๋ฉด, 100๊ฐ์ ์์ฑ์๋ฅผ ํธ์ถํ๊ฒ ๋๋ฏ๋ก ์๋๊ฐ ์กฐ๊ธ ๋๋ฆฌ์ง๋ง, ์ธ๋ฆฌ์ผ์ ์ธ์คํด์ค์ CDO ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ณต์ฌ๋ง ํ๊ธฐ ๋๋ฌธ์ ์๋๊ฐ ์กฐ๊ธ์ด๋๋ง ๋นจ๋ผ์ง๋ค.
๋ํ ๋คํธ์ํฌ๋ฅผ ํตํ ๋ฐ์ดํฐ ์ ์ก ์, ์ฌ๋ฌ ์ธ์คํด์ค์ ์ ๋ณด๋ฅผ ์ฒ์๋ถํฐ ์ ๋ฌํ ํ์ ์์ด CDO์ ๋ด์ฉ๊ณผ ์ฐจ์ด์ ๋ง ์ ๋ฌํ๋ฉด ๋๋ฏ๋ก ๋์ญํญ์ด ์ค์ด๋ ๋ค๋ ์ฅ์ ์ด ์๋ค.
ํ์ง๋ง, ๊ฒ์์ด ์คํ๋๊ณ ์๋ ์ํฉ์์ CDO๋ฅผ ์์ ํ๋ ๊ฑด ์ธ์ด๋ธ ํ์ผ์ด๋ ์ฌ๋ฌ ์์คํ ๋ค๊ณผ์ ํธํ์ฑ์ ์ ํดํ๋ ํ๋์ด๊ธฐ ๋๋ฌธ์ CDO๋ฅผ ๊ฒ์ ์คํ ์ค์๋ ์์ ํ๋ฉด ์๋๋ค.