UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ObjectHandle.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Containers/Map.h"
7#include "CoreTypes.h"
9#include "HAL/Platform.h"
11#include "Templates/TypeHash.h"
12#include "UObject/NameTypes.h"
15#include "UObject/ObjectRef.h"
18
19class UClass;
20class UPackage;
21
26#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
27
29{
31}
32
33using FObjectHandle = UE::CoreUObject::Private::FObjectHandlePrivate;
34
35#elif UE_WITH_REMOTE_OBJECT_HANDLE
36
38{
40}
41
42using FObjectHandle = UE::CoreUObject::Private::FRemoteObjectHandlePrivate;
43
44#else
45
47//NOTE: operator==, operator!=, GetTypeHash fall back to the default on UObject* or void* through coercion.
48
49#endif
50
54
55//Private functions that forced public due to inlining.
57{
58#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
59
61 {
62 //Stores either FPackedObjectRef or a UObject*
63 // Pointer union member is for constinit initialization where we want the linker to be able to do relocations for us within a binary.
64 union
65 {
67 const void* Pointer;
68 };
69
71 {
72 return PointerOrRef;
73 }
74
75 explicit inline operator bool() const
76 {
77 return PointerOrRef != 0;
78 }
79
80 // When using TSAN, PointerOrRef has non-trivial copy construction so we need to explicitly implement constructors to handle the union.
81 // This means this type can't use aggregate initialization even when TSAN is disabled
83 : PointerOrRef(0)
84 {
85 }
86 ~FObjectHandlePrivate() = default;
87 [[nodiscard]] constexpr explicit FObjectHandlePrivate(const void* InPointer)
88 : Pointer(InPointer)
89 {
90 }
91 [[nodiscard]] explicit FObjectHandlePrivate(UPTRINT Packed)
92 : PointerOrRef(Packed)
93 {
94 }
95#if USING_THREAD_SANITISER || USING_INSTRUMENTATION
97 {
99 {
100 Pointer = Other.Pointer;
101 }
102 else
103 {
104 PointerOrRef = Other.PointerOrRef;
105 }
106 }
107 constexpr FObjectHandlePrivate& operator=(const FObjectHandlePrivate& Other)
108 {
110 {
111 Pointer = Other.Pointer;
112 }
113 else
114 {
115 PointerOrRef = Other.PointerOrRef;
116 }
117 return *this;
118 }
119#else // USING_THREAD_SANITISER || USING_INSTRUMENTATION
120 constexpr FObjectHandlePrivate(const FObjectHandlePrivate&) = default;
121 constexpr FObjectHandlePrivate& operator=(const FObjectHandlePrivate&) = default;
122#endif // USING_THREAD_SANITISER || USING_INSTRUMENTATION
123
124 };
125
126 /* Returns the packed object ref for this object IF one exists otherwise returns a null PackedObjectRef */
128
129 /* Creates and ObjectRef from a packed object ref*/
131
132
133#elif UE_WITH_REMOTE_OBJECT_HANDLE
134
136 {
137 // Stores either FRemoteObjectStub* or a UObject*
138 // Pointer union member is for constinit initialization where we want the linker to be able to do relocations for us within a binary.
139 union
140 {
142 const void* Pointer;
143 };
144
145 FRemoteObjectHandlePrivate() = default;
146 explicit constexpr FRemoteObjectHandlePrivate(UObject* Object)
147 : Pointer(Object)
148 {
149 }
151 {
153 }
154
156 {
158 }
159
160 COREUOBJECT_API FRemoteObjectId GetRemoteId() const;
161
164 };
165
166#endif
167
169
170 /* Makes a resolved FObjectHandle from an UObject. */
171 inline constexpr FObjectHandle MakeObjectHandle(UObject* Object);
172
173 /* Returns the UObject from Handle and the handle is updated cache the resolved UObject */
175
176 /* Returns the UClass for UObject store in Handle. Handle is not resolved */
178
179 /* Returns the UObject from Handle and the handle is updated cache the resolved UObject.
180 * Does not cause ObjectHandleTracking to fire a read event
181 */
183
186
189}
190
192
193/* return true if handle is null */
195{
196#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
197 return !Handle.PointerOrRef;
198#elif UE_WITH_REMOTE_OBJECT_HANDLE
199 return !Handle.PointerOrHandle;
200#else
201 return !Handle;
202#endif
203}
204
205/* checks if a handle is resolved.
206 * nullptr counts as resolved
207 * all handles are resolved when late resolved is off
208 */
210{
211#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
212 return !(Handle.PointerOrRef & 1);
213#elif UE_WITH_REMOTE_OBJECT_HANDLE
214 if (!!(Handle.PointerOrHandle & 1))
215 {
216 return false;
217 }
218 else if (!IsObjectHandleNull(Handle))
219 {
220 return !UE::RemoteObject::Handle::IsRemote(ReadObjectHandlePointerNoCheck(Handle));
221 }
222 return true;
223#else
224 return true;
225#endif
226}
227
228/* checks if a handle is resolved.
229 * nullptr counts as resolved
230 * all handles are resolved when late resolved is off
231 */
233{
234#if UE_WITH_REMOTE_OBJECT_HANDLE
235 // Unlike the non-GC version we don't check if the object (if still exists locally) is marked as Remote
236 return !(Handle.PointerOrHandle & 1);
237#else
239#endif
240}
241
242/* return true if a handle is type safe.
243 * null and resolved handles are considered type safe
244 */
246{
247#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE && UE_WITH_OBJECT_HANDLE_TYPE_SAFETY
248 return !((Handle.PointerOrRef & 3) == 3);
249#elif UE_WITH_REMOTE_OBJECT_HANDLE
250 return true;
251#else
252 return true;
253#endif
254}
255
257#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
258inline bool operator==(UE::CoreUObject::Private::FObjectHandlePrivate LHS, UE::CoreUObject::Private::FObjectHandlePrivate RHS)
259{
260 using namespace UE::CoreUObject::Private;
261
264
265 //if both resolved or both unresolved compare the uintptr
267 {
268 return LHS.PointerOrRef == RHS.PointerOrRef;
269 }
270
271 //only one side can be resolved
272 if (LhsResolved)
273 {
274 //both sides can't be null as resolved status would have be true for both
276 if (!Obj)
277 {
278 return false;
279 }
280
281 //if packed ref empty then can't be equal as RHS is an unresolved pointer
283 if (PackedLhs.EncodedRef == 0)
284 {
285 return false;
286 }
287 return PackedLhs.EncodedRef == RHS.PointerOrRef;
288
289 }
290 else
291 {
292 //both sides can't be null as resolved status would have be true for both
293 const UObject* Obj = ReadObjectHandlePointerNoCheck(RHS);
294 if (!Obj)
295 {
296 return false;
297 }
298
299 //if packed ref empty then can't be equal as RHS is an unresolved pointer
301 if (PackedRhs.EncodedRef == 0)
302 {
303 return false;
304 }
305 return PackedRhs.EncodedRef == LHS.PointerOrRef;
306 }
307
308}
309
310inline bool operator!=(UE::CoreUObject::Private::FObjectHandlePrivate LHS, UE::CoreUObject::Private::FObjectHandlePrivate RHS)
311{
312 return !(LHS == RHS);
313}
314
315inline uint32 GetTypeHash(UE::CoreUObject::Private::FObjectHandlePrivate Handle)
316{
317 using namespace UE::CoreUObject::Private;
318
319 if (Handle.PointerOrRef == 0)
320 {
321 return 0;
322 }
323
325 {
327
329 if (PackedObjectRef.EncodedRef == 0)
330 {
331 return GetTypeHash(Obj);
332 }
333 return GetTypeHash(PackedObjectRef.EncodedRef);
334 }
335 return GetTypeHash(Handle.GetPointerOrRef());
336}
337#elif UE_WITH_REMOTE_OBJECT_HANDLE
338inline bool operator==(UE::CoreUObject::Private::FRemoteObjectHandlePrivate LHS, UE::CoreUObject::Private::FRemoteObjectHandlePrivate RHS)
339{
340 using namespace UE::CoreUObject::Private;
341 using namespace UE::RemoteObject::Handle;
342
345
346 //if both resolved or both unresolved compare the uintptr
348 {
349 return LHS.PointerOrHandle == RHS.PointerOrHandle;
350 }
351
352 //only one side can be resolved
353 if (bLhsResolved)
354 {
355 //both sides can't be null as resolved status would have be true for both
357 if (!Obj)
358 {
359 return false;
360 }
361
362 const FRemoteObjectStub* RhsStub = RHS.ToStub();
363 return RhsStub->Id == FRemoteObjectId((const UObjectBase*)Obj);
364 }
365 else
366 {
367 //both sides can't be null as resolved status would have be true for both
368 const UObject* Obj = ReadObjectHandlePointerNoCheck(RHS);
369 if (!Obj)
370 {
371 return false;
372 }
373
374 const FRemoteObjectStub* LhsStub = LHS.ToStub();
375 return LhsStub->Id == FRemoteObjectId((const UObjectBase*)Obj);
376 }
377
378}
379
380inline bool operator!=(UE::CoreUObject::Private::FRemoteObjectHandlePrivate LHS, UE::CoreUObject::Private::FRemoteObjectHandlePrivate RHS)
381{
382 return !(LHS == RHS);
383}
384
385inline FRemoteObjectId GetRemoteObjectId(UE::CoreUObject::Private::FRemoteObjectHandlePrivate Handle)
386{
387 using namespace UE::CoreUObject::Private;
388 using namespace UE::RemoteObject::Handle;
389
390 if (Handle.PointerOrHandle == 0)
391 {
392 return FRemoteObjectId();
393 }
394
396 {
398 return FRemoteObjectId((const UObjectBase*)Obj);
399 }
400 const FRemoteObjectStub* Stub = Handle.ToStub();
401 return Stub->Id;
402}
403
407inline uint32 GetTypeHash(UE::CoreUObject::Private::FRemoteObjectHandlePrivate Handle)
408{
410}
411#endif
412
414
416{
417#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
418 inline constexpr FObjectHandle MakeObjectHandle(UObject* Object)
419 {
421 {
422 return FObjectHandle(Object);
423 }
424 else
425 {
426 return FObjectHandle(UPTRINT(Object));
427 }
428 }
429#elif UE_WITH_REMOTE_OBJECT_HANDLE
430 inline constexpr FObjectHandle MakeObjectHandle(UObject* Object)
431 {
432 return FObjectHandle(Object);
433 }
434#else
435 inline constexpr FObjectHandle MakeObjectHandle(UObject* Object)
436 {
437 return Object;
438 }
439#endif
440
442 {
443#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE || UE_WITH_OBJECT_HANDLE_TRACKING
446 return ResolvedObject;
447#elif UE_WITH_REMOTE_OBJECT_HANDLE
449 return ResolvedObject;
450#else
452#endif
453 }
454
455#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
457 {
458 return FPackedObjectRef{ Handle.PointerOrRef };
459 }
460#endif
461
463 {
464#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
466 {
468 return Obj != nullptr ? UE::CoreUObject::Private::GetClass(Obj) : nullptr;
469 }
470 else
471 {
472 // @TODO: OBJPTR: This should be cached somewhere instead of resolving on every call
475 return ObjectRef.ResolveObjectRefClass();
476 }
477#elif UE_WITH_REMOTE_OBJECT_HANDLE
478 UObject* Obj = nullptr;
480 {
482 }
483 else
484 {
486 if (UClass* Class = Stub->Class.GetClass())
487 {
488 return Class;
489 }
490 else
491 {
493 }
494 }
495 return Obj != nullptr ? UE::CoreUObject::Private::GetClass(Obj) : nullptr;
496#else
498 return Obj != nullptr ? UE::CoreUObject::Private::GetClass(Obj) : nullptr;
499#endif
500 }
501
503 {
504#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
507 {
509 return ResolvedObject;
510 }
511 else
512 {
515 UObject* ResolvedObject = ObjectRef.Resolve();
516#if UE_WITH_OBJECT_HANDLE_TYPE_SAFETY
518#endif
519 {
521 }
522 return ResolvedObject;
523 }
524#elif UE_WITH_REMOTE_OBJECT_HANDLE
526 UObject* ResolvedObject = nullptr;
527 if (!!(LocalHandle.PointerOrHandle & 1))
528 {
530
531 }
533 {
535 }
536 else
537 {
540 return ResolvedObject;
541 }
543 return ResolvedObject;
544#else
546#endif
547 }
548
549
563
565 {
566#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
570 UObject* ResolvedObject = ObjectRef.Resolve();
571#if UE_WITH_OBJECT_HANDLE_TYPE_SAFETY
573#endif
574 {
577 }
578 return ResolvedObject;
579#elif UE_WITH_REMOTE_OBJECT_HANDLE
581 // Unresolved handle may mean two things: we still have the remote object memory (it hasn't been GC'd yet) or we only have a stub
582 UObject* ResolvedObject = nullptr;
584 {
586 }
587 else
588 {
590 }
593 return ResolvedObject;
594#else
596#endif
597 }
598
600 {
601#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
602 return reinterpret_cast<UObject*>(Handle.GetPointerOrRef());
603#elif UE_WITH_REMOTE_OBJECT_HANDLE
604 return reinterpret_cast<UObject*>(Handle.PointerOrHandle);
605#else
606 return Handle;
607#endif
608 }
609
610 //Natvis structs
617
623
625 {
628
629 static constexpr uint32 WeakObjectMask = ~((~0u) >> 1); //most significant bit
630 static constexpr uint32 SimpleNameMask = WeakObjectMask >> 1; //second most significant bits
631 };
632
638
640 {
641 static constexpr const int32 NumInlineElements = 3;
643
644 union
645 {
648 };
649 };
650
651 inline constexpr uint32 TypeIdShift = 1;
652 inline constexpr uint32 ObjectIdShift = 2;
653 inline constexpr uint32 PackageIdShift = 34;
654 inline constexpr uint32 PackageIdMask = 0x3FFF'FFFF;
655
656#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
657 //forward declarations
659 void FreeObjectHandle(const UObjectBase* Object);
660 void UpdateRenamedObject(const UObject* Obj, FName NewName, UObject* NewOuter);
661 UE::CoreUObject::Private::FPackedObjectRef MakePackedObjectRef(const UObject* Object);
662#endif
663}
#define TSAN_ATOMIC(Type)
Definition CoreMiscDefines.h:147
#define UE_IF_CONSTEVAL
Definition Platform.h:786
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::UPTRINT UPTRINT
An unsigned integer the same size as a pointer.
Definition Platform.h:1146
#define UE_FORCEINLINE_HINT
Definition Platform.h:723
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::FPlatformRWLock FRWLock
Definition CriticalSection.h:56
UE_FORCEINLINE_HINT bool operator!=(const FIndexedPointer &Other) const
Definition LockFreeList.h:76
const bool
Definition NetworkReplayStreaming.h:178
bool IsObjectHandleNull(FObjectHandle Handle)
Definition ObjectHandle.h:194
UObject * FObjectHandle
Definition ObjectHandle.h:46
bool IsObjectHandleTypeSafe(FObjectHandle Handle)
Definition ObjectHandle.h:245
bool IsObjectHandleResolved_ForGC(FObjectHandle Handle)
Definition ObjectHandle.h:232
bool IsObjectHandleResolved(FObjectHandle Handle)
Definition ObjectHandle.h:209
uint32 Size
Definition VulkanMemory.cpp:4034
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition NameTypes.h:617
Definition ScriptArray.h:328
Definition Class.h:3793
Definition UObjectBase.h:59
FORCEINLINE UClass * GetClass() const
Definition UObjectBase.h:217
Definition Object.h:95
Definition Package.h:216
uint32 GetTypeHash(const FKey &Key)
Definition BlackboardKey.h:35
bool operator==(const FCachedAssetKey &A, const FCachedAssetKey &B)
Definition AssetDataMap.h:501
Definition CoreGlobals.cpp:268
UObject * ReadObjectHandlePointerNoCheck(FObjectHandle Handle)
Definition ObjectHandle.h:599
constexpr FObjectHandle MakeObjectHandle(UObject *Object)
these functions are always defined regardless of UE_WITH_OBJECT_HANDLE_LATE_RESOLVE value
Definition ObjectHandle.h:435
UObject * NoResolveObjectHandleNoRead(const FObjectHandle &Handle)
Definition ObjectHandle.h:550
constexpr uint32 ObjectIdShift
Definition ObjectHandle.h:652
UObject * ResolveObjectHandleNoReadNoCheck(FObjectHandle &Handle)
Definition ObjectHandle.h:564
constexpr uint32 TypeIdShift
Definition ObjectHandle.h:651
UObject * ResolveObjectHandleNoRead(FObjectHandle &Handle)
Definition ObjectHandle.h:502
UObject * ResolveObjectHandle(FObjectHandle &Handle)
Definition ObjectHandle.h:441
UClass * ResolveObjectHandleClass(FObjectHandle Handle)
Definition ObjectHandle.h:462
UClass * GetClass(UObject *Obj)
Definition ObjectFwd.cpp:8
constexpr uint32 PackageIdMask
Definition ObjectHandle.h:654
void OnHandleRead(const UObject *Object)
Definition ObjectHandleTracking.h:131
constexpr uint32 PackageIdShift
Definition ObjectHandle.h:653
Definition RemoteObject.cpp:483
bool IsRemote(FRemoteObjectId ObjectId)
Definition RemoteObject.cpp:535
UObject * ResolveObject(const FRemoteObjectStub *Stub, ERemoteReferenceType RefType)
Definition RemoteObject.cpp:698
void TouchResidentObject(UObject *Object)
Definition RemoteObject.cpp:763
U16 Index
Definition radfft.cpp:71
Definition NameTypes.h:439
Definition RemoteObjectTypes.h:212
FObjectPathIdDebug ObjectPath
Definition ObjectHandle.h:635
FObjectHandleDataClassDescriptor ClassDescriptor
Definition ObjectHandle.h:636
FMinimalName ClassName
Definition ObjectHandle.h:621
FMinimalName PackageName
Definition ObjectHandle.h:620
FMinimalName PackageName
Definition ObjectHandle.h:613
uint8 _Padding[sizeof(FRWLock)]
Definition ObjectHandle.h:615
FScriptArray ObjectDescriptors
Definition ObjectHandle.h:614
uint32 Number
Definition ObjectHandle.h:627
static constexpr uint32 WeakObjectMask
Definition ObjectHandle.h:629
static constexpr uint32 SimpleNameMask
Definition ObjectHandle.h:630
static constexpr const int32 NumInlineElements
Definition ObjectHandle.h:641
FMinimalName Short[NumInlineElements]
Definition ObjectHandle.h:646
FMinimalName * Long
Definition ObjectHandle.h:647
int32 NumElements
Definition ObjectHandle.h:642
Definition RemoteObject.h:118
FRemoteObjectId Id
Definition RemoteObject.h:119