언리얼 엔진 본캠프 9주차-3 언리얼 엔진 C++ : 타이머 에러

정재훈·2025년 2월 12일
0

unreal engine

목록 보기
27/45

강의 코드를 따라했을 때 잘 되다가 마지막에 파티클을 추가하고 이 파티클에 타이머를 달아서 삭제하려고 했을 때 문제가 발생했다

파티클을 삭제하는 코드는 다음과 같다

캐릭터가 아이템과 Overlap되면 Item은 ActivateItem()가 호출되고, 그 안에서 파티클을 생성해서 보여주고 2초 뒤에 삭제되도록 한 코드이다.

에디터에서 실행해보면

시간이 2초 보다 덜 남았을 때 아이템을 먹어 파티클을 생성하면 SetTimer()로 2초 뒤에 파티클을 삭제하는데, 제한 시간이 0초가 되어 다음 레벨로 넘어가게 된다

다음 레벨로 넘어가면 Level에 있는 Actor들이 삭제가 되고, 이후에 SetTimer()의 Lambda가 호출되는 데 이때 이미 Particle 객체가 삭제가 되어 DestroyComponent()를 호출할 수가 없어 발생한 에러였다.

  • 일반 포인터는 삭제가 되어도 가리키는 주소는 여전히 같은 주소를 가리키고 있음
  • 반면에 포인터가 가리키는 내용물은 없어짐 그래서 C++에서도 많이 본 것처럼 쓰레기 값이 들어가 있는(삭제된) 주소에 있는 걸 읽을라고 하니까 에러 발생
    • 지금까지 C++에서 읽기 엑세스 에러 발생한 경우는 아마 전부 delete한 객체에 접근을 할 때 발생했었다

문제는 알았지만 어떻게 해결해야 할지 감이 안잡혀서 튜터님께 여쭤보니 스마트 포인터를 사용하면 에러를 피할 수 있다는 것을 보여주셨다

다음 코드처럼 TWeakObjectPtr<>을 추가하고 Lambda 함수 부분을 약간 수정했다

이렇게 하고 나니 에러가 발생하지 않았다

그럼 "왜 TWeakObjectPtr<>를 사용하면 괜찮을까?"인데 TWeakObjectPtr<>과 일반 포인터의 차이(?), 특징을 알아야 한다

TWeakPtr은 레퍼런스 카운트를 증가시키지 않아 포인터의 생명 주기에는 관여하지 않음 => 포인터가 garbage collection에 의해 메모리 수거될 수 있음 => 만약 수거되더라도 TWeakPtr에서 해당 포인터의 유효성 체크를 할 수 있음

TWeakObjectPtr<>의 경우에는 포인터가 가리키고 있는 객체가 유효한지를 판단할 수 있음

  • 해당 코드를 실행했을 때 log에 항상 Not Valid만 출력이 됨
  • 이걸로 미뤄보면 Level이 전환될 때 기존 Level에 있던 Actor들은 모두 삭제가 되고 TWeakObjectPtr<>.InValid()는 해당 객체에 대한 유효성 검사를 제대로 하기 때문에 Not Valid만 출력이 되는 것

일반 포인터의 경우에는

  • IsValid() 함수를 보면 포인터(nullptr인지 아닌지) 뿐만 아니라 내부적으로 어떤 Flag를 확인해서 유효성을 검사하는데,
    • (일단 Lambda 캡쳐에서 Particle을 복사해오기 때문에 외부 Partcle이 사라진다고해서 Lambda의 Particle에 영향이 오지는 않음 => nullptr이 아님)
  • 일반 포인터에 대해서는 Flag 확인 부분에서 제대로 동작을 하지 않았다는 것을 유추할 수 있고
  • 이 때문에 일반 포인터에서는 IsValid()로 유효성 검사를 제대로 할 수 없다는 것이다
일단 UPROPERTY()가 없는 일반 포인터는 리플렉션 시스템에 등록이 안되기 때문에 Flag 확인 하는 부분에서 이상하게 동작하는 것 같음

따라서 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

profile
드가자

0개의 댓글