위크 포인터(Weak Pointer) 는 오브젝트에 대한 약한 참조를 저장합니다. 쉐어드 포인터(Shared Pointers) 또는 쉐어드 레퍼런스(Shared References) 와 달리 위크 포인터는 참조하는 오브젝트의 파괴를 방지하지 않습니다.
위크 포인터가 참조하는 오브젝트에 액세스하기 전에 Pin 함수를 사용하여 위크 포인터를 생성해야 합니다. 이렇게 하면 오브젝트를 사용하는 동안 계속 존재하게 됩니다. 위크 포인터가 오브젝트를 참조하는지 여부만 설정하면 되는 경우 이를 nullptr 과 비교하거나 IsValid 를 호출할 수 있습니다.
위크 포인터를 사용하면 의도를 부여하는 데 도움이 될 수 있습니다. 위크 포인터는 참조된 오브젝트에 대한 소유권 없는 관찰을 수행하며 해당 오브젝트의 수명을 제어하지 않습니다.
선언, 초기화, 할당
빈 위크 포인터를 만들거나 쉐어드 레퍼런스, 쉐어드 포인터 또는 다른 위크 포인터에서 빌드할 수 있습니다.
// 새 데이터 오브젝트를 할당하고 이에 대한 강한 참조를 만듭니다.
TSharedRef<FMyObjectType> ObjectOwner = MakeShared<FMyObjectType>();
// 새 데이터 오브젝트에 위크 포인터를 생성합니다.
TWeakPtr<FMyObjectType> ObjectObserver(ObjectOwner);
위크 포인터는 오브젝트가 파괴되는 것을 방지하지 않습니다. 이 예시에서 ObjectOwner 를 재설정하면 ObjectObserver 가 여전히 범위 내에 있는지 여부에 관계없이 오브젝트가 파괴됩니다.
// ObjectOwner가 해당 오브젝트의 유일한 오너라고 가정할 때 ObjectOwner가 참조를 중단하면 해당 오브젝트가 삭제됩니다.
ObjectOwner.Reset();
// Pin()이 생성하는 쉐어드 포인터 null 오브젝트를 참조하는 ObjectOwner로 인해 null이 됩니다. 부울로 처리될 때 빈 쉐어드 포인터는 false로 평가됩니다.
if (ObjectObserver.Pin())
{
// 이 코드는 ObjectOwner가 오브젝트의 유일한 오너가 아닌 경우에만 실행됩니다.
check(false);
}
위크 포인터는 유효한 오브젝트를 참조하는지 여부에 관계없이 쉐어드 포인터와 마찬가지로 안전하게 복사할 수 있습니다.
TWeakPtr<FMyObjectType> AnotherObjectObserver = ObjectObserver;
작업이 끝나면 위크 포인터를 재설정할 수 있습니다.
// 위크 포인터를 nullptr로 설정하여 재설정할 수 있습니다.
ObjectObserver = nullptr;
// Reset 함수를 사용할 수도 있습니다.
AnotherObjectObserver.Reset();
쉐어드 포인터로 변환하기
Pin 함수는 위크 포인터의 오브젝트에 대한 쉐어드 포인터를 생성합니다. 쉐어드 포인터가 범위 내에 있고 오브젝트를 참조하는 한 오브젝트는 유효한 상태로 유지됩니다. 또한 쉐어드 포인터( Pin 함수에서 반환된 포인터 포함)는 조건부로 bool 유형으로 평가될 수 있으며 여기서 true 는 유효한 오브젝트를 나타냅니다. 다음 코드 패턴은 위크 포인터가 유효한 오브젝트를 참조하는지 확인하고, 유효한 경우 적어도 쉐어드 포인터(Pin 함수에 의해 생성)가 범위를 벗어나거나 명시적으로 지워질 될 때까지 계속 유효하도록 합니다.
// 위크 포인터에서 쉐어드 포인터를 획득하고 유효한 오브젝트를 참조하는지 확인합니다.
if (TSharedPtr<FMyObjectType> LockedObserver = ObjectObserver.Pin())
{
// 쉐어드 포인터는 이 범위 내에서만 유효합니다.
// 오브젝트가 존재하는 것으로 확인되었으며 쉐어드 포인터가 해당 오브젝트의 삭제를 방지합니다.
LockedObserver->SomeFunction();
}
역참조 및 액세스
위크 포인터의 오브젝트에 액세스하려면 먼저 Pin 함수를 사용하여 쉐어드 포인터로 승격하세요. 그런 다음 쉐어드 포인터나 위크 포인터에서 Get 함수를 통해 액세스할 수 있습니다. 이 메서드를 사용하면 작업하는 동안 오브젝트가 유효한 상태로 유지됩니다.
레퍼런스 순환 깨기
두 개 이상의 오브젝트가 서로에 대해 강한 참조를 유지하기 위해 스마트 포인터를 사용할 때마다 레퍼런스 순환이 존재합니다. 이때 오브젝트가 항상 다른 오브젝트에 의해 참조되어, 오브젝트가 삭제되지 않도록 서로를 보호하기 때문에 다른 오브젝트가 아직 존재하는 동안에는 어느 오브젝트도 삭제할 수 없습니다. 외부 오브젝트가 레퍼런스 순환의 오브젝트 중 하나를 참조하지 않으면 누출됩니다. 위크 포인터는 참조하는 오브젝트를 유지하지 않기 때문에 이러한 레퍼런스 순환을 깨뜨릴 수 있습니다. 오브젝트에 대한 오너십을 주장하지 않고 잠재적으로 수명을 연장하지 않으면서 오브젝트를 참조하려면 위크 포인터를 사용하세요.
사용 경고
위크 포인터는 데이터 오브젝트가 계속 존재하는 것을 보장하고 싶지 않지만, 바로 이 프로퍼티가 위험할 수 있는 경우에 유용합니다. 위크 포인터를 사용할 때 다음 상황에서 주의가 필요합니다.
-
사용량은 세트 또는 맵의 키입니다. 위크 포인터는 언제든지 무효화될 수 있고 컨테이너에 알리지 않으므로 쉐어드 포인터 또는 쉐어드 레퍼런스가 키 역할에 더 적합합니다. 위크 포인터는 값으로 사용하기에 안전합니다.
-
위크 포인터는
IsValid함수를 제공하지만IsValid를 확인한다고 해서 오브젝트가 일정 기간 동안 유효한 상태로 유지된다는 보장은 없습니다. 스레드 세이프 쉐어드 포인터가 좋은 예시입니다. 다른 스레드의 활동으로 인해 언제든지 유효하지 않게 될 수 있기 때문입니다.Pin함수는 저장된 오브젝트를 역참조하거나 액세스하는 검사에 선호되는 방법입니다.Pin이 반환하는 쉐어드 포인터는 코드가 오브젝트를 지우거나 범위를 벗어날 때까지 오브젝트를 활성 상태로 유지하기 때문입니다.