강의 코드를 따라했을 때 잘 되다가 마지막에 파티클을 추가하고 이 파티클에 타이머를 달아서 삭제하려고 했을 때 문제가 발생했다
파티클을 삭제하는 코드는 다음과 같다
캐릭터가 아이템과 Overlap되면 Item은 ActivateItem()가 호출되고, 그 안에서 파티클을 생성해서 보여주고 2초 뒤에 삭제되도록 한 코드이다.
에디터에서 실행해보면
시간이 2초 보다 덜 남았을 때 아이템을 먹어 파티클을 생성하면 SetTimer()로 2초 뒤에 파티클을 삭제하는데, 제한 시간이 0초가 되어 다음 레벨로 넘어가게 된다
다음 레벨로 넘어가면 Level에 있는 Actor들이 삭제가 되고, 이후에 SetTimer()의 Lambda가 호출되는 데 이때 이미 Particle 객체
가 삭제가 되어 DestroyComponent()
를 호출할 수가 없어 발생한 에러였다.
문제는 알았지만 어떻게 해결해야 할지 감이 안잡혀서 튜터님께 여쭤보니 스마트 포인터를 사용하면 에러를 피할 수 있다는 것을 보여주셨다
다음 코드처럼 TWeakObjectPtr<>
을 추가하고 Lambda 함수 부분을 약간 수정했다
이렇게 하고 나니 에러가 발생하지 않았다
그럼 "왜 TWeakObjectPtr<>
를 사용하면 괜찮을까?"인데 TWeakObjectPtr<>
과 일반 포인터의 차이(?), 특징을 알아야 한다
TWeakObjectPtr<>
의 경우에는 포인터가 가리키고 있는 객체가 유효한지를 판단할 수 있음
TWeakObjectPtr<>
의 .InValid()
는 해당 객체에 대한 유효성 검사를 제대로 하기 때문에 Not Valid만 출력이 되는 것일반 포인터의 경우에는
IsValid()
함수를 보면 포인터(nullptr인지 아닌지) 뿐만 아니라 내부적으로 어떤 Flag를 확인해서 유효성을 검사하는데, IsValid()
로 유효성 검사를 제대로 할 수 없다는 것이다따라서 TWeakObjectPtr<>
은 유효성 검사를 제대로 해서 DestroyComponent() 함수를 호출하지 않기 때문에 에러가 발생하지 않는 것이고, 일반 포인터는 유효성 검사가 제대로 안된 경우가 있을 수 있고 이 경우에 DestroyComponent()를 호출하기 때문에 에러가 발생한 것이었다.
참조 사이트
1. https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-object-handling-in-unreal-engine
2. https://forums.unrealengine.com/t/whats-the-difference-between-using-tweakobjectptr-or-using-uobject/284354
3. https://community.gamedev.tv/t/should-i-only-declare-raw-pointers-as-uproperty/232878/6
4. https://forums.unrealengine.com/t/non-uproperty-uobject-garbage-collection/439082
5. https://velog.io/@luz0415/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%97%94%EC%A7%84-%ED%8F%AC%EC%9D%B8%ED%84%B0
6. https://www.reddit.com/r/unrealengine/comments/osqia3/how_much_should_i_be_using_smart_pointers/
7. https://linkmemo.tistory.com/216