쉐어드 포인터는 기본적으로 메모리 누수를 방지하고 초기화되지 않은 메모리에 대한 포인터를 방지한다는 점에서 기본 스마트 포인터의 모든 이점을 포함하고 있으며 다음과 같은 추가 기능들도 제공합니다.
- 공유 소유권 : 여러 쉐어드 포인터가 참조하는 데이터 개체는 참조 카운트가 0이 되지 않는 한 소멸되지 않습니다.
- 자동 무효화 : 댕글링 포인터에 대한 걱정없이 안전하게 참조할 수 있습니다.
- 약한 참조 : 위크 포인터는 참조 주기를 깰 수 있습니다.
- 의도의 표시 : 소유자를 관찰자와 구별하고 무효화할 수 없는 참조를 제공합니다.
쉐어드 포인터에는 주목할 만한 몇가지 기본 특성이 존재합니다.
- 매우 견고한 신택스
- 비간섭
- 스레드 안전
- 좋은 성능, 메모리 관리
쉐어드 포인터에는 위와 같은 기능들과 특징이 존재하기 때문에 많이 사용되고 있습니다.
이제 쉐어드 포인터의 사용법에 대해 알아보도록 하겠습니다.
1. 선언 및 초기화
// Create an empty shared pointer
TSharedPtr<FMyObjectType> EmptyPointer;
// Create a shared pointer to a new object
TSharedPtr<FMyObjectType> NewPointer(new FMyObjectType());
// Create a Shared Pointer from a Shared Reference
TSharedRef<FMyObjectType> NewReference(new FMyObjectType());
TSharedPtr<FMyObjectType> PointerFromReference = NewReference;
// Create a Thread-safe Shared Pointer
TSharedPtr<FMyObjectType, ESPMode::ThreadSafe> NewThreadsafePointer = MakeShared<FMyObjectType, ESPMode::ThreadSafe>(MyArgs);
위 예제 코드처럼 쉐어드 포인터를 선언하고 초기화하는 여러가지 방법들이 있습니다.
// Increase the reference count of whatever object ExistingSharedPointer references.
TSharedPtr<FMyObjectType> AnotherPointer = ExistingSharedPointer;
그리고 쉐어드 포인터를 복사할때마다 시스템은 참조하는 개체에 대한 참조 카운트를 한개씩 증가시킵니다.
여기서 참조된 개체는 참조하는 쉐어드 포인터가 한개라도 존재한다면 소멸되지 않고 유지됩니다.
PointerOne.Reset();
PointerTwo = nullptr;
// Both PointerOne and PointerTwo now reference nullptr.
Reset() 함수를 사용하여 쉐어드 포인터를 재설정하거나 null 포인터를 할당할 수 있습니다.
// Move the contents of PointerOne over to PointerTwo. PointerOne will reference nullptr after this.
PointerTwo = MoveTemp(PointerOne);
// Move the contents of PointerTwo over to PointerOne. PointerTwo will reference nullptr after this.
PointerOne = MoveTempIfPossible(PointerTwo);
MoveTemp() 함수를 사용하여 하나의 쉐어드 포인터의 내용을 다른 쉐어드 포인터로 전송할 수 있습니다.
전송된 이후에 파라미터로 넘겨준 쉐어드 포인터는 null 포인터가 됩니다.
2. 쉐어드 포인터와 쉐어드 레퍼런스 간에 변환
쉐어드 포인터와 쉐어드 레퍼런스 간에 변환하는 것은 일반적인 방법입니다.
TSharedPtr<FMyObjectType> MySharedPointer = MySharedReference;
쉐어드 레퍼런스는 암시적으로 쉐어드 포인터로 변환하고 쉐어드 포인터가 유효한 개체를 참조할 것이라는 추가 보증을 제공합니다. 위 예제 코드처럼 쉐어드 레퍼런스 => 쉐어드 포인터 로의 변환은 할당 연산자를 통해 암시적으로 변환이 가능합니다.
// Ensure your shared pointer is valid before dereferencing to avoid a potential assertion.
if (MySharedPointer.IsValid())
{
MySharedReference = MySharedPointer.ToSharedRef();
}
쉐어드 포인터가 null이 아닌 개체를 참조하는 한 ToSharedRef() 함수를 사용하여 쉐어드 레퍼런스를 만들 수 있습니다.
쉐어드 포인터가 null인 상태에서 쉐어드 레퍼런스를 만들려고 시도하면 어서트가 발생하게 됩니다.
3. 비교
TSharedPtr<FTreeNode> NodeA, NodeB;
if (NodeA == NodeB)
{
// ...
}
쉐어드 포인터는 operator==을 사용하여 비교할 수 있습니다.
여기서 비교하는 부분은 두 쉐어드 포인터가 동일한 개체를 참조하는지에 대한 것입니다.
if (Node.IsValid())
{
// ...
}
if (Node)
{
// ...
}
if (Node.Get() != nullptr)
{
// ...
}
IsValid() 함수 또는 쉐어드 포인터 자체를 사용하여 유효한 개체를 참조하는지를 판단할 수 있습니다.
그리고 Get() 함수를 사용하여 쉐어드 포인터가 유효한 개체 포인터를 반환하는지도 확인할 수 있습니다.
4. 참조 및 액세스 해제
// Check that Node references a valid object before dereferencing.
if (Node)
{
// Any of the following three lines of code will dereference Node and call ListChildren on its object:
Node->ListChildren();
Node.Get()->ListChildren();
(*Node).ListChildren();
}
위 예제 코드처럼 ListChildren() 함수를 사용하여 개체에 대한 참조 해제 및 액세스 해제를 할 수 있습니다.
참조 해제를 하기 전에 쉐어드 포인터의 타당성 검사를 하는 것을 잊지 마시기 바랍니다.
5. 사용자 지정 삭제기
void DestroyMyObjectType(FMyObjectType* ObjectAboutToBeDeleted)
{
// Custom deletion code goes here.
}
// These functions create Smart Pointers with custom deleters.
TSharedRef<FMyObjectType> NewReference(new FMyObjectType(), [](FMyObjectType* Obj){ DestroyMyObjectType(Obj); });
TSharedPtr<FMyObjectType> NewPointer(new FMyObjectType(), [](FMyObjectType* Obj){ DestroyMyObjectType(Obj); });
쉐어드 포인터와 쉐어드 레퍼런스는 참조하는 개체에 대한 사용자 지정 삭제기를 지원합니다.
사용자 지정 삭제 코드를 실행하려면 위 예제 코드처럼 스마트 포인터를 생성할때 파라미터로 실행하려는 람다 함수를 넘겨주면 됩니다.
'언리얼 C++ 프로그래밍' 카테고리의 다른 글
[언리얼 C++] 위크 포인터 사용법 (0) | 2021.07.23 |
---|---|
[언리얼 C++] 쉐어드 레퍼런스 사용법 (0) | 2021.07.22 |
[언리얼 C++] 스마트 포인터 라이브러리 (2) (0) | 2021.07.20 |
[언리얼 C++] 스마트 포인터 라이브러리 (1) (0) | 2021.07.19 |
[언리얼 C++] 언리얼 오브젝트 처리 (2) (0) | 2021.07.18 |