[UE5] 스마트 포인터, 하드 레퍼런스, 소프트 레퍼런스

김영웅·2025년 2월 19일

스마트 포인터

TSharedPtr

C++ STL의 shared_ptr과 유사하다.

TSharedPtr<HealingPotion> ItemPtr = MakeShared<HealingPotion>();
이처럼 선언해 사용할 수 있다.

  • IsValid() : 현재 이 포인터가 유효한지를 검사
  • Get() : 일반(Raw) 포인터를 반환한다.
  • Reset()이나 nullptr을 대입해 참조 카운트를 줄일 수 있다.
    참조 카운터가 0이 되면 가비지 컬렉터가 수거할 수 있는 상태가 된다.

TSharedRef

TSharedPtr과 비슷하지만 Reference 상태인 만큼 nullptr로 만드는게 불가능하다.
그렇기에 null 검사를 하지 않아도 되고, 안전하다.

아래와 같이 Ptr -> Ref로 바꿀 수 있다.

TSharedPtr<HealingPotion> ItemPtr = MakeShared<HealingPotion>();
TSharedRef<HealingPotion> ItemRef = ItemPtr.ToSharedRef();

TWeakPtr

TSharedPtr과 유사하지만 큰 차이점이 있는데
이 타입은 레퍼런스 카운트를 증가시키지 않는다.
고로 항상 사용할 때 IsValid()로 검사를 해줘야됨

그럼 이걸 왜 쓰나 싶지만
이 말은 즉 이 타입은 대상의 생명 주기에 관여하지 않기 때문에 어떤 객체의 모니터링 등에 유용하게 쓰인다.

TUniquePtr

C++의 unique_ptr과 똑같다.
다른 레퍼런스를 다른 스마트 포인터와 공유할 수 없다.

다음과 같이 생성과 이동을 할 수 있다.

TUniquePtr<HealingPotion> uHP = MakeUnique<HealingPotion>();
TUniquePtr<HealingPotion> uHP2 = MoveTemp(uHP); //옮기기 전용 함수 MoveTemp 사용

하드 레퍼런스와 소프트 레퍼런스

위의 소개한 스마트 포인터로 쉽게 변수를 관리할 수 있다.
하지만 만약 UObject에 스마트 포인터 변수가 멤버 변수로서 선언된다면, UObject가 사라지기 전까지는 레퍼런스 카운트가 0이 된다고 하여 스마트 포인터의 메모리를 해제하지 않는다.

가비지 컬렉터가 UObject를 수거하기 전까지 해당 변수가 살아있는거다.

이전에 공부했던 강참조, 약참조가 이 내용이다.

하드 레퍼런스

대표적

  • UPROPERTY()를 사용하여 선언된 오브젝트
UPROPERTY()
UStaticMeshComponent *MeshComp;
  • TObjectPtr<UObject>
    위에 있는 UPROPERTY()와 동일하지만, nullptr과 Dangling을 방지해주기 때문에 써주는게 좋다.
    UPROPERTY()가 붙으면 GC가 관리하게 된다.
    그럼에도 GC내 수거시 자동으로 내부를 nullptr로 만들지 않기 때문에 사용시 마다 유효성 체크가 필요하다

  • TStringObjectPtr<UObject>
    UPROPERTY 처럼 리플랙션 속성을 명시적으로 받아가기 원하지 않는 경우만 사용한다.
    나머지 동작이나 속성은 TObjectPtr과 동일하다.

특징

  • 게임 로딩이나 레벨 로딩시 같이 메모리에 로드 되므로 중간 끊김이 없음.
  • 항상 로드되어 존재하므로 메모리 사용량이 증가하며, 따로 관리하지 않으면 메모리에 계속 남아있게 됨.
  • 언리얼 레벨에 속해있는 하드 레퍼런스 오브젝트의 경우 레벨과 같이 로드/언로드 된다

소프트 레퍼런스

이전에 약참조를 공부하면서 봤듯이 결국 게임 시작 시 바로 로딩하는 것이 아닌 나중에 로딩하는 것이 핵심이다.

대표적

  • TSoftObjectPtr
  • TWeakObjectPtr
  • FSoftObjectPath

중간에 Object 단어가 들어간 이유는 위에서 언급된 스마트 포인터에 비해 UObject에서 상속된 객체 전용으로 디자인되어 있기 때문이다.

특징

  • 비동기 로딩을 지원

  • DLC나 게임 로딩 때 사용

소프트 레퍼런스를 사용하면 로딩을 수동으로 해줘야한다
LoadSynchronous()를 사용해 로딩할 수 있다.

TSoftObjectPtr<UTexture2D> SoftTexture = TSoftObjectPtr<UTexture2D>(FSoftObjectPath(TEXT("/Game/Textures/MyTexture")));
UTexture2D* LoadedTexture = SoftTexture.LoadSynchronous()

해제 시에는 아래처럼 사용한다.

FStreamableManager& StreamableManager = UAssetManager::GetStreamableManager();
StreamableManager.Unload(SoftTexture.ToSoftObjectPath());

// 필요에 따라 명시적인 GC 호출이 필요하기도 함.
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
profile
게임 프로그래머

0개의 댓글