TSharedPtr
reference counting
을 사용하여 객체의 수명을 관리한다. 여러 객체가 같은 인스턴스를 공유하며, 마지막 참조가 사라질 때 자동으로 메모리를 해제한다.
선언 및 초기화
null
을 허용하므로 데이터 오브젝트 사용 여부에 관계없이 초기화할 수 있다.
// 빈 SharedPtr 생성
TSharedPtr<FMyObjectType> EmptyPointer;
// 새 오브젝트에 SharedPtr 생성
TSharedPtr<FMyObjectType> NewPointer(new FMyObjectType());
// SharedRef 에서 SharedPtr 생성
TSharedRef<FMyObjectType> NewReference(new FMyObjectType());
TSharedPtr<FMyObjectType> PointerFromReference = NewReference;
// Thread Safe SharedPtr 생성
TSharedPtr<FMyObjectType, ESPMode::ThreadSafe> NewThreadsafePointer =
MakeShared<FMyObjectType, ESPMode::ThreadSafe>(MyArgs);
// Reset 함수를 사용하거나 nullptr를 할당하며 SharedPtr을 재설정
PointerOne.Reset();
PointerTwo = nullptr;
// MoveTemp 함수를 사용해 다른 SharedPtr로 이동할 수 있다
// PointerOne의 콘텐츠를 PointerTwo로 이동 (PointerOne == nullptr)
PointerTwo = MoveTemp(PointerOne);
SharedPtr 과 SharedRef 간 변환
SharedRef는 암시적으로 SharedPtr로 변환되며, 새 SharedPtr이 유효한 오브젝트를 참조한다는 것을 보장한다.
TSharedPtr<FMyObjectType> MySharedPointer = MySharedReference;
SharedPtr이 null이 아닌 오브젝트를 참조하면 SharedPtr 함수인 ToSharedRef
를 사용해 SharedRef를 생성할 수 있다. null
인 오브젝트를 참조하는 SharedPtr에서 SharedRef를 생성하려고 하면 프로그램이 assert
를 발생시킨다.
if( MySharedPointer.IsValid() )
{
MySharedReference = MySharedPointer.ToSharedRef();
}
비교
두 SharedPtr
이 동일한 오브젝트를 참조하면 같은 것으로 판단한다.
TSharedPtr<FTreeNode> NodeA, NodeB;
if(NodeA == NodeB) { ... }
IsValid
와 bool
연산자는 SharedPtr
가 유효한 오브젝트를 참조하는지 여부를 확인한다. 또한 Get
을 호출하여 유효한 오브젝트 포인터를 반환하는지 확인할 수도 있다.
역참조 및 접근
일반 C++ 포인터와 동일한 방식으로 역참조하고, 메서드를 호출하며, 멤버에 접근할 수 있다. 모든 C++ 포인터와 마찬가지로 역참조하기 전에는 IsValid
함수를 호출하거나 오버로드된 bool
연산자를 사용하여 null
검사를 수행해야 한다.
TSharedRef
참조하는 오브젝트를 소유한다는 면에서 TSharedPtr
와 같은 역할을 하지만, TSharedRef
는 반드시 유효한 객체를 가리켜야 한다. TSharedRef
는 언제나 TSharedPtr
로 변환될 수 있다.
TSharedRef
은 다른 오브젝트를 참조하도록 재설정하거나, null
오브젝트를 할당하거나, 빈 오브젝트를 생성할 수 없다. 항상 유효한 오브젝트가 포함되며, IsValid
메서드도 없다.
선언 및 초기화
null
을 허용하지 않으므로 초기화에는 오브젝트가 필요하다.
TSharedRef<FMyObjectType> NewReference = MakeShared<FMyObjectType>();
TWeakPtr
TSharedPtr
로 관리되는 객체에 대한 약한 참조를 제공한다. 참조 카운트에 영향을 주지 않으면서, 객체의 존재 여부를 확인할 수 있다. 따라서 참조하는 오브젝트의 소멸을 방지하지 못한다. Pin
함수를 통해 TSharedPtr
로 변환 후 안전하게 객체에 접근해야 한다.
선언, 초기화, 할당
// 새 데이터 오브젝트를 할당하고 이에 대한 강한 참조를 만든다
TSharedRef<FMyObjectType> ObjectOwner = MakeShared<FMyObjectType>();
// 새 데이터 오브젝트에 TWeakPtr 생성
TWeakPtr<FMyObjectType> ObjectObserver(ObjectOwner);
ObjectOwner
를 Reset
하면, ObjectObserver
가 범위 내에 있는지 여부에 관계 없이 오브젝트가 파괴된다.
// ObjectOwner가 해당 오브젝트의 유일한 오너라면, 해당 오브젝트가 삭제된다.
ObjectOwner.Reset();
// null 오브젝트를 참조하는 ObjectOwner로 인해 null이 되며, false로 평가된다.
if (ObjectObserver.Pin()){ ... }
// 유효한 오브젝트를 참조하는지에 관계 없이 복사 가능
TWeakPtr<FMyObjectType> AnotherObjectObserver = ObjectObserver;
// 작업이 끝나면 Reset 가능
ObjectObserver = nullptr;
AnotherObjectObserver.Reset();
TSharedPtr로 변환
Pin
함수는 TWeakPtr
의 오브젝트에 대한 TSharedPtr
을 생성한다.
if (TSharedPtr<FMyObjectType> LockedObserver = ObjectObserver.Pin())
{
// TSharedPtr은 이 범위 내에서만 유효
LockedObserver->SomeFunction();
}
역참조 및 액세스
Pin
함수를 사용하여 TSharedPtr
로 승격한 후, Get
함수를 통해 액세스해야 한다.
TUniquePtr
유일한 소유권을 가진 스마트 포인터. 오직 하나의 TUniquePtr
만 객체를 소유하며, 소유권 이전만 가능하여 복사를 막으며, 범위를 벗어나면 자동으로 객체를 파괴하여 메모리 누수를 방지한다.
TUniquePtr
가 참조하는 오브젝트에 SharedPtr
또는 SharedRef
를 생성하면 위험하다. 다른 스마트 포인터들이 오브젝트를 여전히 참조하고 있음에도 불구하고, 유니크 포인터가 소멸되면 해당 오브젝트가 함께 소멸되기 때문이다. 마찬가지로, SharedPtr
또는 SharedRef
가 가리키는 오브젝트에 UniquePtr
를 생성하지 않는 것을 권장한다.
주의할 점
UObject
는 언리얼의 GC에 의해 관리되는 객체이므로 일반 C++ 스마트 포인터를 UObject
에 직접 사용할 수 없다. UObject
를 참조할 때는 TWeakObjectPtr
을 사용할 수 있다. UObject
에 특화된 약한 참조로, 객체가 이미 파괴되었는지 안전하게 확인할 수 있도록 돕는다.