20250219 -TweakObjectptr-

초보 게임개발자·2025년 2월 19일
0

UnrealEngine

목록 보기
10/18

오늘은 TweakObjecptr 에 대해서 공부를 했다
공부를 하게된 이유는 이번주도 언리얼과 C++을 활용해서 아이템이 자동으로 스폰되고 사라지고 일정 시간이 지나면 다음 Wave 진행 특정 Wave단계 까지 지나면 다음 Level로 넘어 가는 식의 간단한 게임 같은걸 만들어 봤는데 어김없이 에러가 발생했습니다.
아이템의 파티클이 특정 시간이 지나면 사라지게 해놓았는데 이 타이밍에 다음 Level로 넘어가게 되면 충돌이 일어나서 게임이 강제 종료되는 그런 에러였습니다.

그래서 뭐 때문에 그렇게 되는지 찾아 보다가 BaseItem, HealingItem, MaineItem 에서 파티클 타임핸들에 문제가 있어서 오류 수정을 하려고 찾아보다가
좀더 안전성이 좋은 TweakObjeptr을 사용해 해결을 해서 이에 대해 설명을 해볼까 합니다.


우선 먼저 사용했던 코드에서 에러가 자꾸 났던 이유는

if (Particle) // Particle이 nullptr이 아닌 경우 실행
{
// 타이머 핸들러 선언
FTimerHandle DestroyParticleTimerHandle;

// 2초 후 실행될 람다 함수 등록
GetWorld()->GetTimerManager().SetTimer(
	DestroyParticleTimerHandle, // 타이머 핸들
	[Particle]() // Particle을 캡처하여 람다에서 직접 사용
	{
		// Particle이 유효하다고 가정하고 바로 삭제
		Particle->DestroyComponent(); 
	},
	2.0f, // 2초 뒤 실행
	false // 반복 실행 여부 (false: 한 번만 실행)
);
}

위 코드는 Particle이 타이머가 실행되기 전에 삭제될 경우 dangling pointer(미사용 메모리를 참조하는 포인터) 문제가 발생할 가능성이 있다고 하는데
Particle이 2초내 다른 코드에서 삭제되면 포인터가 dangling pointer가 되어 충돌(segmentation fault) 가능성이 있어 문제가 발생할수 있다고 합니다.

그래서 이부분을 보완 하고자 해서

if (Particle) // Particle이 nullptr이 아닌 경우 실행
{
// 타이머 핸들러 선언
FTimerHandle DestroyParticleTimerHandle;

// Particle을 약한 참조(Weak Pointer)로 저장
TWeakObjectPtr<UParticleSystemComponent> WeakParticle = Particle;

// 2초 후 실행될 람다 함수 등록
GetWorld()->GetTimerManager().SetTimer(
	DestroyParticleTimerHandle, // 타이머 핸들
	[WeakParticle]() // 약한 참조를 캡처하여 사용
	{
		// Particle이 아직 유효한지 확인
		if (WeakParticle.IsValid()) 
		{
			// 유효한 경우에만 삭제
			WeakParticle->DestroyComponent();
		}
	},
	2.0f, // 2초 뒤 실행
	false // 반복 실행 여부 (false: 한 번만 실행)
);
}

TWeakObjectPtr을 사용하여 Particle이 아직 유효한지 확인 (IsValid())
Particle이 2초 내에 삭제되어도 문제없이 안전하게 처리됩니다.

결론: 첫 번째 코드에서는 Particle이 2초 내에 삭제될 경우 dangling pointer 문제로 충돌이 발생할 수 있음.
두 번째 코드에서는 TWeakObjectPtr을 사용하여 유효성 검사를 하기 때문에 안전하게 삭제 가능!

따라서, 게임 개발에서 동적 객체를 다룰 때는 항상 TWeakObjectPtr을 고려하는 것이 좋을것 같다.


TWeakObjectPtr의 역할과 기능

TWeakObjectPtr은 유효성 검사를 수행할 수 있는 약한 참조(Weak Pointer) 입니다.
즉, 객체의 존재 여부를 확인하면서 안전하게 접근할 수 있도록 해주는 스마트 포인터입니다.

1. 왜 필요할까?

게임 개발에서는 UObject 기반 객체(예: AActor, UActorComponent 등)가 Garbage Collection(GC) 에 의해 자동으로 메모리에서 해제됩니다.
그런데 일반 포인터(UObject*)로 객체를 참조하면, 객체가 삭제된 후에도 포인터가 남아 있을 수 있어 메모리 충돌(segmentation fault)이 발생할 수 있습니다.
예를 들어, 다음과 같은 경우 문제가 발생할 수 있음:

UParticleSystemComponent* Particle = GetParticleComponent();
if (Particle)
{
// 2초 후에 Particle을 삭제하는 코드 실행
Particle->DestroyComponent();
}

// Particle이 삭제된 후에도 여전히 포인터를 사용하려고 하면 충돌 발생 가능!
Particle->SetVisibility(false); // 메모리 충돌 가능 (dangling pointer)

해결책: TWeakObjectPtr을 사용하면 IsValid()로 유효성을 검사한 후 안전하게 접근 가능!

2. TWeakObjectPtr의 기능

    1. 객체를 직접 소유하지 않음 (메모리 해제에 관여하지 않음)
      TWeakObjectPtr은 강한 참조를 하지 않기 때문에 Garbage Collector(GC)의 영향을 받음.
      즉, 객체가 삭제되면 TWeakObjectPtr는 자동으로 nullptr로 무효화됨.
    1. 객체가 살아 있는지 확인 가능
      IsValid()를 사용하면 객체가 유효한지 확인 가능.
      Pin()을 사용하면 객체가 살아 있는 동안 안전하게 TStrongObjectPtr 또는 일반 포인터로 변환 가능.

3. 기본적인 사용법

TWeakObjectPtr WeakActor = SomeActor;
if (WeakActor.IsValid()) // 객체가 아직 유효한지 확인
{
WeakActor->Destroy(); // 안전하게 사용 가능
}

IsValid()가 false이면 WeakActor가 이미 GC에 의해 삭제되었음을 의미.


결론

TWeakObjectPtr은 UObject의 안전한 참조를 위한 스마트 포인터.
IsValid()로 유효성 검사 후 사용해야 함.
Garbage Collection(GC)과 함께 동작하기 때문에 UObjects를 다룰 때 강력한 도구!

최근데 여러가지 에러를 겪고 해결에 나아가면서 개인적으로 이론공부를 할 때보다 더 많이 배우고 있는거 같고 왜 다양한 트러블이슈들을 겪어 봐야 한다는지 온몸으로 느끼고 있는 중입니다.

profile
기록은 기억을 지배한다!

0개의 댓글

관련 채용 정보