EM_Task/CoreUObject/Public/UObject/StrongObjectPtr.h
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

168 lines
4.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "UObject/GCObject.h"
#include "Templates/EnableIf.h"
#include "Templates/PointerIsConvertibleFromTo.h"
#include "Templates/UniquePtr.h"
namespace UE4StrongObjectPtr_Private
{
class FInternalReferenceCollector: public FGCObject
{
public:
explicit FInternalReferenceCollector(const volatile UObject* InObject)
: Object(InObject)
{
check(IsInGameThread());
}
virtual ~FInternalReferenceCollector()
{
check(IsInGameThread() || IsInGarbageCollectorThread());
}
bool IsValid() const
{
return Object != nullptr;
}
template <typename UObjectType>
FORCEINLINE UObjectType* GetAs() const
{
return (UObjectType*)Object;
}
FORCEINLINE void Set(const volatile UObject* InObject)
{
Object = InObject;
}
//~ FGCObject interface
virtual void AddReferencedObjects(FReferenceCollector& Collector) override
{
Collector.AddReferencedObject(Object);
}
virtual FString GetReferencerName() const override
{
return "UE4StrongObjectPtr_Private::FInternalReferenceCollector";
}
private:
const volatile UObject* Object;
};
} // namespace UE4StrongObjectPtr_Private
/**
* Specific implementation of FGCObject that prevents a single UObject-based pointer from being GC'd while this guard is in scope.
* @note This is the "full-fat" version of FGCObjectScopeGuard which uses a heap-allocated FGCObject so *can* safely be used with containers that treat types as trivially relocatable.
*/
template <typename ObjectType>
class TStrongObjectPtr
{
public:
TStrongObjectPtr(TStrongObjectPtr&& InOther) = default;
TStrongObjectPtr& operator=(TStrongObjectPtr&& InOther) = default;
~TStrongObjectPtr() = default;
FORCEINLINE_DEBUGGABLE TStrongObjectPtr(TYPE_OF_NULLPTR = nullptr)
{
static_assert(TPointerIsConvertibleFromTo<ObjectType, const volatile UObject>::Value, "TStrongObjectPtr can only be constructed with UObject types");
}
FORCEINLINE_DEBUGGABLE explicit TStrongObjectPtr(ObjectType* InObject)
{
static_assert(TPointerIsConvertibleFromTo<ObjectType, const volatile UObject>::Value, "TStrongObjectPtr can only be constructed with UObject types");
Reset(InObject);
}
FORCEINLINE_DEBUGGABLE TStrongObjectPtr(const TStrongObjectPtr& InOther)
{
Reset(InOther.Get());
}
template <
typename OtherObjectType,
typename = decltype(ImplicitConv<ObjectType*>((OtherObjectType*)nullptr))>
FORCEINLINE_DEBUGGABLE TStrongObjectPtr(const TStrongObjectPtr<OtherObjectType>& InOther)
{
Reset(InOther.Get());
}
FORCEINLINE_DEBUGGABLE TStrongObjectPtr& operator=(const TStrongObjectPtr& InOther)
{
Reset(InOther.Get());
return *this;
}
template <
typename OtherObjectType,
typename = decltype(ImplicitConv<ObjectType*>((OtherObjectType*)nullptr))>
FORCEINLINE_DEBUGGABLE TStrongObjectPtr& operator=(const TStrongObjectPtr<OtherObjectType>& InOther)
{
Reset(InOther.Get());
return *this;
}
FORCEINLINE_DEBUGGABLE ObjectType& operator*() const
{
check(IsValid());
return *Get();
}
FORCEINLINE_DEBUGGABLE ObjectType* operator->() const
{
check(IsValid());
return Get();
}
FORCEINLINE_DEBUGGABLE bool IsValid() const
{
return ReferenceCollector && ReferenceCollector->IsValid();
}
FORCEINLINE_DEBUGGABLE explicit operator bool() const
{
return IsValid();
}
FORCEINLINE_DEBUGGABLE ObjectType* Get() const
{
return ReferenceCollector ? ReferenceCollector->GetAs<ObjectType>() : nullptr;
}
FORCEINLINE_DEBUGGABLE void Reset(ObjectType* InNewObject = nullptr)
{
if (ReferenceCollector)
{
ReferenceCollector->Set(InNewObject);
}
else if (InNewObject)
{
ReferenceCollector = MakeUnique<UE4StrongObjectPtr_Private::FInternalReferenceCollector>(InNewObject);
}
}
FORCEINLINE_DEBUGGABLE friend uint32 GetTypeHash(const TStrongObjectPtr& InStrongObjectPtr)
{
return GetTypeHash(InStrongObjectPtr.Get());
}
private:
TUniquePtr<UE4StrongObjectPtr_Private::FInternalReferenceCollector> ReferenceCollector;
};
template <typename LHSObjectType, typename RHSObjectType>
FORCEINLINE bool operator==(const TStrongObjectPtr<LHSObjectType>& InLHS, const TStrongObjectPtr<RHSObjectType>& InRHS)
{
return InLHS.Get() == InRHS.Get();
}
template <typename LHSObjectType, typename RHSObjectType>
FORCEINLINE bool operator!=(const TStrongObjectPtr<LHSObjectType>& InLHS, const TStrongObjectPtr<RHSObjectType>& InRHS)
{
return InLHS.Get() != InRHS.Get();
}