언리얼 C++ 프로그래밍

[언리얼 C++] 위크 포인터 사용법

언린이 2021. 7. 23. 22:02

위크 포인터는 개체에 대한 약한 참조를 저장합니다. 쉐어드 포인터 또는 쉐어드 레퍼런스와 달리 위크 포인터는 참조하는 개체의 소멸을 방지하지 않습니다.

그렇기 때문에 위크 포인터가 참조하는 개체에 액세스하기 전에 쉐어드 포인터로 만들어야 합니다. 이렇게 하면 개체를 사용하는 동안 개체가 계속 존재할 수 있습니다.

 

 

1. 선언, 초기화 및 할당

// Allocate a new data object and create a strong reference to it.
TSharedRef<FMyObjectType> ObjectOwner = MakeShared<FMyObjectType>();

// Create a weak pointer to the new data object.
TWeakPtr<FMyObjectType> ObjectObserver(ObjectOwner);

빈 위크 포인터를 만들거나 쉐어드 레퍼런스, 쉐어드 포인터 또는 위크 포인터를 통해 위크 포인터를 생성할 수 있습니다.

 

// Assuming ObjectOwner was the only owner of its object, that object will be destroyed when ObjectOwner stops referencing it.
ObjectOwner.Reset();

// The Shared Pointer that Pin() generates will be null due to ObjectOwner referencing a null object. When treated as a bool, empty Shared Pointers evaluate to false.
if (ObjectObserver.Pin())
{
    // This code will run only if ObjectOwner was not the sole owner of our object.
    check(false);
}

위크 포인터는 개체가 소멸되는 것을 방지하지 않습니다. 위 예제 코드에서는 재설정이 범위에 있는지 여부에 관계없이 개체가 파괴됩니다.

 

TWeakPtr<FMyObjectType> AnotherObjectObserver = ObjectObserver;

위크 포인터는 유효한 개체를 참조하는지 여부에 관계없이 쉐어드 포인터와 마찬가지로 안전하게 복사할 수 있습니다.

 

// You can reset a Weak Pointer by setting it to nullptr.
ObjectObserver = nullptr;

// You can also use the Reset function.
AnotherObjectObserver.Reset();

위크 포인터는 nullptr 할당이나 Reset() 함수를 사용하여 재설정할 수 있습니다.

 

 

2. 쉐어드 포인터로 변환

// Acquire a Shared Pointer from the Weak Pointer and check that it references a valid object.
if (TSharedPtr<FMyObjectType> LockedObserver = ObjectObserver.Pin())
{
    // The Shared Pointer is valid only within this scope.
    // The object has been verified to exist, and the Shared Pointer prevents its deletion.
    LockedObserver->SomeFunction();
}

Pin() 함수는 위크 포인터의 개체에 대한 쉐어드 포인터를 생성합니다. 쉐어드 포인터가 범위에 있고 개체를 참조하는 한 개체는 유효하게 유지됩니다. 또한 Pin() 함수에서 반환된 포인터를 포함하여 유효한 개체를 나타내는 조건부 형식으로 평가할 수 있습니다. 위 예제 코드는 위크 포인터가 유효한 개체를 참조하는지 확인하고, 그렇다면 쉐어드 포인터가 범위를 벗어나거나 명시적으로 지워질때까지 유효하도록 보장합니다.

 

 

3. 참조 및 액세스

위크 포인터의 개체에 액세스하기 위해 먼저 위의 Pin() 함수를 사용하여 쉐어드 포인터로 만들어 줍니다.

그런 다음 쉐어드 포인터의 Get() 함수를 사용하여 개체에 액세스할 수 있습니다.

 

 

4. 참조 주기 끊기

두개 이상의 개체가 스마트 포인터를 사용하여 서로에 대한 강한 참조를 유지할때 참조 주기가 존재하게 됩니다.

이러한 상황에서 개체는 각 개체가 항상 다른 개체에서 참조되므로 소멸로부터 서로를 보호하게 되어서 다른 개체가 여전히 존재하는 한 둘 다 소멸되지 않습니다.

위크 포인터는 위크 포인터가 참조하는 개체를 보존하지 않기 때문에 이러한 참조 주기를 깰 수 있습니다. 그래서 소유권을 주장하고 수명을 연장하지 않고 개체를 참조하려는 경우 위크 포인터를 사용합니다.

 

 

5. 위크 포인터 사용시 주의사항

위크 포인터는 데이터 개체가 계속 존재하도록 보장하지 않으려는 경우에 유용하지만 이 특징은 위험할 수 있습니다.

위크 포인터를 사용할때 다음과 같은 상황에 주의가 필요합니다.

  • TSet 또는 TMap의 Key로 사용해선 안됩니다. 위크 포인터는 언제든지 유효하지 않을 수 있으며 컨테이너에 알리지 않으므로 쉐어드 포인터 또는 쉐어드 레퍼런스가 Key 역할을 하는데 더 적합합니다. 위크 포인터는 Value로 사용할 수 있습니다.
  • 위크 포인터가 Pin() 함수를 제공하지만 확인을 통해 개체가 유효하게 유지되는 것은 아닙니다. 스레드 안전성이 있는 쉐어드 포인터는 다른 스레드의 활동으로 인해 언제든지 유효하지 않게 될 수 있기 때문에 특히 그렇습니다. Pin() 함수로 반환되는 쉐어드 포인터는 소멸되거나 범위를 벗어날때까지 개체를 유지하므로 저장된 개체를 참조하거나 액세스하는 것이 바람직한 방법입니다.