오늘은 언리얼엔진 스마트포인터에 대해서 알아봤습니다.

언리얼 엔진이 제공하는 스마트 포인터에는 TSharedPtr, TWeakPtr, TUniquePtr이 있습니다.

 

1. TSharedPtr (참조 카운팅 스마트 포인터)란?

  • TSharedPtr은 참조 카운트 기반의 스마트 포인터이며 여러 개의 TSharedPtr이 같은 객체를 공유할 수 있습니다.
  • TSharedPtr이 소멸될 때 객체가 자동으로 삭제됩니다.
  • TSharedPtr은 nullptr이 될 수 있으므로 IsValid()를 이용한 체크가 가능합니다.

 

예시 코드

#include "CoreMinimal.h"
#include <iostream>

class FMyObject
{
public:
    FMyObject() { UE_LOG(LogTemp, Warning, TEXT("FMyObject 생성")); }
    ~FMyObject() { UE_LOG(LogTemp, Warning, TEXT("FMyObject 삭제")); }

    void PrintMessage() { UE_LOG(LogTemp, Warning, TEXT("Hello from FMyObject!")); }
};

void TestSharedPtr()
{
    TSharedPtr<FMyObject> Ptr1 = MakeShared<FMyObject>();  // 객체 생성 및 참조 카운트 1 증가
    {
        TSharedPtr<FMyObject> Ptr2 = Ptr1;  // 참조 카운트 2 증가
        Ptr2->PrintMessage();
    }  // Ptr2가 범위를 벗어나면서 참조 카운트 1 감소

    UE_LOG(LogTemp, Warning, TEXT("Ptr1 남아 있음"));
}  // Ptr1이 범위를 벗어나면서 객체가 자동 삭제됨

 

 

2. TWeakPtr (약한 참조, 순환 참조 방지)란?

  • TSharedPtr을 직접 보유하지 않고, 약한 참조를 제공합니다.
  • 참조 카운트를 증가시키지 않아 순환 참조 문제를 방지합니다.
  • 객체가 삭제됐는지 확인하려면 .Pin()을 사용해야 합니다.
  • TWeakPtr은 객체를 직접 사용하지 못하며, Pin()을 사용해 TSharedPtr 로 변환한 후 사용해야 합니다.

 

예시 코드

class FParent;
class FChild;

class FParent
{
public:
    TSharedPtr<FChild> Child;
    ~FParent() { UE_LOG(LogTemp, Warning, TEXT("FParent 삭제")); }
};

class FChild
{
public:
    TWeakPtr<FParent> Parent;  // TWeakPtr 사용하여 순환 참조 방지
    ~FChild() { UE_LOG(LogTemp, Warning, TEXT("FChild 삭제")); }
};

void TestWeakPtr()
{
    TSharedPtr<FParent> Parent = MakeShared<FParent>();
    TSharedPtr<FChild> Child = MakeShared<FChild>();

    Parent->Child = Child;
    Child->Parent = Parent;  // TWeakPtr 사용 순환 참조 문제 회피

    UE_LOG(LogTemp, Warning, TEXT("TestWeakPtr 종료"));
}  // Parent, Child가 범위를 벗어나면서 정상적으로 삭제됨
TWeakPtr<FMyObject> WeakPtr = MySharedPtr;

if (TSharedPtr<FMyObject> ValidPtr = WeakPtr.Pin()) 
{
    ValidPtr->PrintMessage();  // 객체가 살아있다면 실행
}
else 
{
    UE_LOG(LogTemp, Warning, TEXT("객체가 삭제됨"));
}

 

 

3. TUniquePtr (단일 소유권 스마트 포인터)란?

  • 하나의 포인터만 객체를 소유할 수 있습니다.
  • 다른 TUniquePtr로 복사할 수 없습니다.
  • MoveTmep()를 사용하여 이동 연산이 가능합니다.
  • 객체가 필요 없어지면 자동으로 삭제됩니다.

 

예시 코드

void TestUniquePtr()
{
    TUniquePtr<FMyObject> UniquePtr = MakeUnique<FMyObject>();
    UniquePtr->PrintMessage();  // 객체 사용

    UniquePtr.Reset();  // 명시적으로 삭제 가능
    if (!UniquePtr) 
    {
        UE_LOG(LogTemp, Warning, TEXT("UniquePtr가 삭제됨"));
    }
}
void MoveUniquePtr(TUniquePtr<FMyObject> NewOwner)
{
    if (NewOwner)
    {
        NewOwner->PrintMessage();
    }
}

void TestMoveUniquePtr()
{
    TUniquePtr<FMyObject> UniquePtr = MakeUnique<FMyObject>();
    MoveUniquePtr(MoveTemp(UniquePtr));  // UniquePtr의 소유권을 이동
    if (!UniquePtr)
    {
        UE_LOG(LogTemp, Warning, TEXT("UniquePtr가 이동됨"));
    }
}

+ Recent posts