언리얼C++ 기초, 알고리즘 1문제
GetWorld()->GetTimerManager().SetTimer(
DestroyParticleTimerHandle,
[Particle]()
{
Particle->DestroyComponent();
},
2.0f,
false
);
Unreal에서 파티클이나 사운드 컴포넌트를 생성한 뒤, 타이머로 몇 초 후 제거. 또는 특정 작업 전에 제거로 하려했다. 그래서 람다에 raw pointer를 그대로 캡처해서 사용했지만,
레벨 전환이나 DestroyComponent()가 먼저 일어나면, 타이머가 실행되는 시점에 Particle이 이미 유효하지 않은 객체가 될 수 있다.
위 코드는 안전해 보이지만, 실제로는 포인터 주소값이 있는지만 확인한다. Unreal의 UObject가 아직 살아있는지까지는 보장하지 않는다.
if(Particle)은 "포인터 주소가 nullptr이 아닌지?" 만 확인한다.
하지만 Unreal에서 객체가 Destroy되었거나 GC 대상이 되었는데도, 포인터 값 자체는 남아 있을 수 있다.
즉 Particle != nullptr이지만 실제 UObject는 이미 유효하지 않는다.
if (Particle)
{
TWeakObjectPtr<UParticleSystemComponent> WeakParticle = Particle;
FTimerHandle DestroyParticleTimerHandle;
GetWorld()->GetTimerManager().SetTimer(
DestroyParticleTimerHandle,
[WeakParticle]()
{
if (WeakParticle.IsValid())
{
WeakParticle->DestroyComponent();
}
},
2.0f,
false
);
}
TWeakObjectPtr은 UObject를 약하게 참조하는 포인터다. 객체의 생명주기에 관여하지않고 객체가 유효한지 확인 할 수 있다.
-> 객체를 붙잡아두지는 않음
-> 객체가 사라졌는지 확인할 수 있음