UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SparseDelegate.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Containers/Array.h"
6#include "Containers/Map.h"
9#include "HAL/PlatformMath.h"
14#include "UObject/NameTypes.h"
15#include "UObject/Object.h"
20
21class FOutputDevice;
22class FString;
23class UObjectBase;
24class UWorld;
25struct FSparseDelegate;
26
38{
39public:
40
42 static COREUOBJECT_API void RegisterDelegateOffset(const UObject* OwningObject, FName DelegateName, size_t OffsetToOwner);
43
45 static COREUOBJECT_API bool Add(const UObject* DelegateOwner, const FName DelegateName, FScriptDelegate Delegate);
46
48 static COREUOBJECT_API bool AddUnique(const UObject* DelegateOwner, const FName DelegateName, FScriptDelegate Delegate);
49
51 static COREUOBJECT_API bool Contains(const UObject* DelegateOwner, const FName DelegateName, const FScriptDelegate& Delegate);
52 static COREUOBJECT_API bool Contains(const UObject* DelegateOwner, const FName DelegateName, const UObject* InObject, FName InFunctionName);
53
55 static COREUOBJECT_API bool Remove(const UObject* DelegateOwner, const FName DelegateName, const FScriptDelegate& Delegate);
56 static COREUOBJECT_API bool Remove(const UObject* DelegateOwner, const FName DelegateName, const UObject* InObject, FName InFunctionName);
57
59 static COREUOBJECT_API bool RemoveAll(const UObject* DelegateOwner, const FName DelegateName, const UObject* UserObject);
60
62 static COREUOBJECT_API void Clear(const UObject* DelegateOwner, const FName DelegateName);
63
66
69
71 static COREUOBJECT_API void SetMulticastDelegate(const UObject* DelegateOwner, const FName DelegateName, FMulticastScriptDelegate Delegate);
72
74 static COREUOBJECT_API FSparseDelegate* ResolveSparseDelegate(const UObject* OwningObject, FName DelegateName);
75
77 static COREUOBJECT_API UObject* ResolveSparseOwner(const FSparseDelegate& SparseDelegate, const FName OwningClassName, const FName DelegateName);
78
81
82private:
83
85 {
86 virtual ~FObjectListener();
87 virtual void NotifyUObjectDeleted(const UObjectBase* Object, int32 Index) override;
88 virtual void OnUObjectArrayShutdown();
89 void EnableListener();
90 void DisableListener();
91
92 virtual SIZE_T GetAllocatedSize() const override
93 {
94 return 0;
95 }
96 };
97
99 friend struct FObjectListener;
100
102 static COREUOBJECT_API FObjectListener SparseDelegateObjectListener;
103
105 static COREUOBJECT_API FTransactionallySafeCriticalSection SparseDelegateMapCritical;
106
109
112
114 static COREUOBJECT_API TMap<TPair<FName, FName>, size_t> SparseDelegateObjectOffsets;
115};
116
119{
120public:
122 : bIsBound(false)
123 {
124 }
125
131 bool IsBound() const
132 {
133 return bIsBound;
134 }
135
151
164 {
165 if (bIsBound)
166 {
168 }
169 }
170
180 void __Internal_Clear(const UObject* DelegateOwner, FName DelegateName)
181 {
182 if (bIsBound)
183 {
185 bIsBound = false;
186 }
187 }
188
189protected:
190
193};
194
196template <typename MulticastDelegate, typename OwningClass, typename DelegateInfoClass>
198{
199public:
200 typedef typename MulticastDelegate::FDelegate FDelegate;
201
202protected:
204 {
205 static const FName DelegateFName(DelegateInfoClass::GetDelegateName());
206 return DelegateFName;
207 }
208
209private:
210 UObject* GetDelegateOwner() const
211 {
212 const size_t OffsetToOwner = DelegateInfoClass::template GetDelegateOffset<OwningClass>();
214 UObject* DelegateOwner = reinterpret_cast<UObject*>((uint8*)this - OffsetToOwner);
215 check(DelegateOwner->IsValidLowLevelFast(false)); // Most likely the delegate is trying to be used on the stack, in an object it wasn't defined for, or for a class member with a different name than it was defined for. It is only valid for a sparse delegate to be used for the exact class/property name it is defined with.
216 return DelegateOwner;
217 }
218
219public:
230
238 {
239 return (bIsBound ? FSparseDelegateStorage::Contains(GetDelegateOwner(), GetDelegateName(), InDelegate) : false);
240 }
241
249 bool Contains(const UObject* InObject, FName InFunctionName) const
250 {
251 return (bIsBound ? FSparseDelegateStorage::Contains(GetDelegateOwner(), GetDelegateName(), InObject, InFunctionName) : false);
252 }
253
263
274
285
293 void Remove(const UObject* InObject, FName InFunctionName)
294 {
295 if (bIsBound)
296 {
297 bIsBound = FSparseDelegateStorage::Remove(GetDelegateOwner(), GetDelegateName(), InObject, InFunctionName);
298 }
299 }
300
310 {
311 if (bIsBound)
312 {
314 }
315 }
316
320 void Clear()
321 {
323 }
324
328 template<typename... ParamTypes>
329 void Broadcast(ParamTypes... Params)
330 {
332 {
333 MCDelegate->Broadcast(Params...);
334 }
335 }
336
348 template< class UserClass >
349 bool __Internal_IsAlreadyBound( UserClass* InUserObject, typename FDelegate::template TMethodPtrResolver< UserClass >::FMethodPtr InMethodPtr, FName InFunctionName ) const
350 {
351 check( InUserObject != nullptr && InMethodPtr != nullptr );
352
353 // NOTE: We're not actually using the incoming method pointer or calling it. We simply require it for type-safety reasons.
354
355 return this->Contains( InUserObject, InFunctionName );
356 }
357
368 template< class UserClass >
369 void __Internal_AddDynamic( UserClass* InUserObject, typename FDelegate::template TMethodPtrResolver< UserClass >::FMethodPtr InMethodPtr, FName InFunctionName )
370 {
371 check( InUserObject != nullptr && InMethodPtr != nullptr );
372
373 // NOTE: We're not actually storing the incoming method pointer or calling it. We simply require it for type-safety reasons.
374
376 NewDelegate.__Internal_BindDynamic( InUserObject, InMethodPtr, InFunctionName );
377
378 this->Add( NewDelegate );
379 }
380
391 template< class UserClass >
392 void __Internal_AddUniqueDynamic( UserClass* InUserObject, typename FDelegate::template TMethodPtrResolver< UserClass >::FMethodPtr InMethodPtr, FName InFunctionName )
393 {
394 check( InUserObject != nullptr && InMethodPtr != nullptr );
395
396 // NOTE: We're not actually storing the incoming method pointer or calling it. We simply require it for type-safety reasons.
397
399 NewDelegate.__Internal_BindDynamic( InUserObject, InMethodPtr, InFunctionName );
400
401 this->AddUnique( NewDelegate );
402 }
403
414 template< class UserClass >
415 void __Internal_RemoveDynamic( UserClass* InUserObject, typename FDelegate::template TMethodPtrResolver< UserClass >::FMethodPtr InMethodPtr, FName InFunctionName )
416 {
417 check( InUserObject != nullptr && InMethodPtr != nullptr );
418
419 // NOTE: We're not actually storing the incoming method pointer or calling it. We simply require it for type-safety reasons.
420
421 this->Remove( InUserObject, InFunctionName );
422 }
423
424private:
425 // Hide internal functions that never need to be called on the derived classes
426 void __Internal_AddUnique(const UObject*, FName, FScriptDelegate);
427 void __Internal_Remove(const UObject*, FName, const FScriptDelegate&);
428 void __Internal_Clear(const UObject*, FName);
429};
430
431#define FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE(SparseDelegateClassName, OwningClass, DelegateName, FuncParamList, FuncParamPassThru, ...) \
432 FUNC_DECLARE_DYNAMIC_MULTICAST_DELEGATE(SparseDelegateClassName##_MCSignature, SparseDelegateClassName##_DelegateWrapper, FUNC_CONCAT(FuncParamList), FUNC_CONCAT(FuncParamPassThru), __VA_ARGS__) \
433 struct SparseDelegateClassName##InfoGetter \
434 { \
435 static const char* GetDelegateName() { return #DelegateName; } \
436 template<typename T> \
437 static size_t GetDelegateOffset() { return offsetof(T, DelegateName); } \
438 }; \
439 struct SparseDelegateClassName : public TSparseDynamicDelegate<SparseDelegateClassName##_MCSignature, OwningClass, SparseDelegateClassName##InfoGetter> \
440 { \
441 };
442
444#define DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName, , FUNC_CONCAT( *this ), void )
445
446#define DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam( SparseDelegateClass, OwningClass, DelegateName, Param1Type, Param1Name ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName, FUNC_CONCAT( Param1Type InParam1 ), FUNC_CONCAT( *this, InParam1 ), void, Param1Type )
447#define DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams( SparseDelegateClass, OwningClass, DelegateName, Param1Type, Param1Name, Param2Type, Param2Name ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName, FUNC_CONCAT( Param1Type InParam1, Param2Type InParam2 ), FUNC_CONCAT( *this, InParam1, InParam2 ), void, Param1Type, Param2Type )
448#define DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_ThreeParams( SparseDelegateClass, OwningClass, DelegateName, Param1Type, Param1Name, Param2Type, Param2Name, Param3Type, Param3Name ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName, FUNC_CONCAT( Param1Type InParam1, Param2Type InParam2, Param3Type InParam3 ), FUNC_CONCAT( *this, InParam1, InParam2, InParam3 ), void, Param1Type, Param2Type, Param3Type )
449#define DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams( SparseDelegateClass, OwningClass, DelegateName, Param1Type, Param1Name, Param2Type, Param2Name, Param3Type, Param3Name, Param4Type, Param4Name ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName, FUNC_CONCAT( Param1Type InParam1, Param2Type InParam2, Param3Type InParam3, Param4Type InParam4 ), FUNC_CONCAT( *this, InParam1, InParam2, InParam3, InParam4 ), void, Param1Type, Param2Type, Param3Type, Param4Type )
450#define DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams( SparseDelegateClass, OwningClass, DelegateName, Param1Type, Param1Name, Param2Type, Param2Name, Param3Type, Param3Name, Param4Type, Param4Name, Param5Type, Param5Name ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName, FUNC_CONCAT( Param1Type InParam1, Param2Type InParam2, Param3Type InParam3, Param4Type InParam4, Param5Type InParam5 ), FUNC_CONCAT( *this, InParam1, InParam2, InParam3, InParam4, InParam5 ), void, Param1Type, Param2Type, Param3Type, Param4Type, Param5Type )
451#define DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SixParams( SparseDelegateClass, OwningClass, DelegateName, Param1Type, Param1Name, Param2Type, Param2Name, Param3Type, Param3Name, Param4Type, Param4Name, Param5Type, Param5Name, Param6Type, Param6Name ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName, FUNC_CONCAT( Param1Type InParam1, Param2Type InParam2, Param3Type InParam3, Param4Type InParam4, Param5Type InParam5, Param6Type InParam6 ), FUNC_CONCAT( *this, InParam1, InParam2, InParam3, InParam4, InParam5, InParam6 ), void, Param1Type, Param2Type, Param3Type, Param4Type, Param5Type, Param6Type )
452#define DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams( SparseDelegateClass, OwningClass, DelegateName, Param1Type, Param1Name, Param2Type, Param2Name, Param3Type, Param3Name, Param4Type, Param4Name, Param5Type, Param5Name, Param6Type, Param6Name, Param7Type, Param7Name ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName, FUNC_CONCAT( Param1Type InParam1, Param2Type InParam2, Param3Type InParam3, Param4Type InParam4, Param5Type InParam5, Param6Type InParam6, Param7Type InParam7 ), FUNC_CONCAT( *this, InParam1, InParam2, InParam3, InParam4, InParam5, InParam6, InParam7 ), void, Param1Type, Param2Type, Param3Type, Param4Type, Param5Type, Param6Type, Param7Type )
453#define DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_EightParams( SparseDelegateClass, OwningClass, DelegateName, Param1Type, Param1Name, Param2Type, Param2Name, Param3Type, Param3Name, Param4Type, Param4Name, Param5Type, Param5Name, Param6Type, Param6Name, Param7Type, Param7Name, Param8Type, Param8Name ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName, FUNC_CONCAT( Param1Type InParam1, Param2Type InParam2, Param3Type InParam3, Param4Type InParam4, Param5Type InParam5, Param6Type InParam6, Param7Type InParam7, Param8Type InParam8 ), FUNC_CONCAT( *this, InParam1, InParam2, InParam3, InParam4, InParam5, InParam6, InParam7, InParam8 ), void, Param1Type, Param2Type, Param3Type, Param4Type, Param5Type, Param6Type, Param7Type, Param8Type )
454#define DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams( SparseDelegateClass, OwningClass, DelegateName, Param1Type, Param1Name, Param2Type, Param2Name, Param3Type, Param3Name, Param4Type, Param4Name, Param5Type, Param5Name, Param6Type, Param6Name, Param7Type, Param7Name, Param8Type, Param8Name, Param9Type, Param9Name ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE( SparseDelegateClass, OwningClass, DelegateName, FUNC_CONCAT( Param1Type InParam1, Param2Type InParam2, Param3Type InParam3, Param4Type InParam4, Param5Type InParam5, Param6Type InParam6, Param7Type InParam7, Param8Type InParam8, Param9Type InParam9 ), FUNC_CONCAT( *this, InParam1, InParam2, InParam3, InParam4, InParam5, InParam6, InParam7, InParam8, InParam9 ), void, Param1Type, Param2Type, Param3Type, Param4Type, Param5Type, Param6Type, Param7Type, Param8Type, Param9Type )
#define check(expr)
Definition AssertionMacros.h:314
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition Platform.h:1150
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
::FCriticalSection FTransactionallySafeCriticalSection
Definition TransactionallySafeCriticalSection.h:16
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint8_t uint8
Definition binka_ue_file_header.h:8
Definition UnrealType.h:6643
Definition NameTypes.h:617
Definition OutputDevice.h:133
Definition UObjectArray.h:984
Definition Array.h:670
Definition UnrealString.h.inl:34
Definition ScriptDelegates.h:509
Definition ScriptDelegates.h:66
Definition SharedPointer.h:692
Definition UObjectBase.h:59
Definition Object.h:95
Definition World.h:918
@ false
Definition radaudio_common.h:23
U16 Index
Definition radfft.cpp:71
Definition SparseDelegate.h:38
static COREUOBJECT_API TSharedPtr< FMulticastScriptDelegate > GetSharedMulticastDelegate(const UObject *DelegateOwner, const FName DelegateName)
Definition SparseDelegate.cpp:99
static COREUOBJECT_API void SparseDelegateReport(const TArray< FString > &, UWorld *, FOutputDevice &)
Definition SparseDelegate.cpp:360
static COREUOBJECT_API FSparseDelegate * ResolveSparseDelegate(const UObject *OwningObject, FName DelegateName)
Definition SparseDelegate.cpp:56
static COREUOBJECT_API FMulticastScriptDelegate * GetMulticastDelegate(const UObject *DelegateOwner, const FName DelegateName)
Definition SparseDelegate.cpp:85
static COREUOBJECT_API bool Remove(const UObject *DelegateOwner, const FName DelegateName, const FScriptDelegate &Delegate)
Definition SparseDelegate.cpp:223
static COREUOBJECT_API void RegisterDelegateOffset(const UObject *OwningObject, FName DelegateName, size_t OffsetToOwner)
Definition SparseDelegate.cpp:50
static COREUOBJECT_API void Clear(const UObject *DelegateOwner, const FName DelegateName)
Definition SparseDelegate.cpp:330
static COREUOBJECT_API bool Add(const UObject *DelegateOwner, const FName DelegateName, FScriptDelegate Delegate)
Definition SparseDelegate.cpp:134
static COREUOBJECT_API bool AddUnique(const UObject *DelegateOwner, const FName DelegateName, FScriptDelegate Delegate)
Definition SparseDelegate.cpp:160
friend struct FObjectListener
Definition SparseDelegate.h:99
static COREUOBJECT_API bool RemoveAll(const UObject *DelegateOwner, const FName DelegateName, const UObject *UserObject)
Definition SparseDelegate.cpp:295
static COREUOBJECT_API bool Contains(const UObject *DelegateOwner, const FName DelegateName, const FScriptDelegate &Delegate)
Definition SparseDelegate.cpp:186
static COREUOBJECT_API UObject * ResolveSparseOwner(const FSparseDelegate &SparseDelegate, const FName OwningClassName, const FName DelegateName)
Definition SparseDelegate.cpp:75
static COREUOBJECT_API void SetMulticastDelegate(const UObject *DelegateOwner, const FName DelegateName, FMulticastScriptDelegate Delegate)
Definition SparseDelegate.cpp:114
Definition SparseDelegate.h:119
FSparseDelegate()
Definition SparseDelegate.h:121
bool bIsBound
Definition SparseDelegate.h:192
void __Internal_Clear(const UObject *DelegateOwner, FName DelegateName)
Definition SparseDelegate.h:180
void __Internal_AddUnique(const UObject *DelegateOwner, FName DelegateName, FScriptDelegate InDelegate)
Definition SparseDelegate.h:147
void __Internal_Remove(const UObject *DelegateOwner, FName DelegateName, const FScriptDelegate &InDelegate)
Definition SparseDelegate.h:163
bool IsBound() const
Definition SparseDelegate.h:131
Definition SparseDelegate.h:198
TSharedPtr< MulticastDelegate > GetShared() const
Definition SparseDelegate.h:221
void Remove(const FScriptDelegate &InDelegate)
Definition SparseDelegate.h:281
FName GetDelegateName() const
Definition SparseDelegate.h:203
void __Internal_AddDynamic(UserClass *InUserObject, typename FDelegate::template TMethodPtrResolver< UserClass >::FMethodPtr InMethodPtr, FName InFunctionName)
Definition SparseDelegate.h:369
void __Internal_RemoveDynamic(UserClass *InUserObject, typename FDelegate::template TMethodPtrResolver< UserClass >::FMethodPtr InMethodPtr, FName InFunctionName)
Definition SparseDelegate.h:415
void Clear()
Definition SparseDelegate.h:320
MulticastDelegate::FDelegate FDelegate
Definition SparseDelegate.h:200
void RemoveAll(const UObject *Object)
Definition SparseDelegate.h:309
bool __Internal_IsAlreadyBound(UserClass *InUserObject, typename FDelegate::template TMethodPtrResolver< UserClass >::FMethodPtr InMethodPtr, FName InFunctionName) const
Definition SparseDelegate.h:349
bool Contains(const FScriptDelegate &InDelegate) const
Definition SparseDelegate.h:237
void AddUnique(FScriptDelegate InDelegate)
Definition SparseDelegate.h:270
void Add(FScriptDelegate InDelegate)
Definition SparseDelegate.h:259
bool Contains(const UObject *InObject, FName InFunctionName) const
Definition SparseDelegate.h:249
void __Internal_AddUniqueDynamic(UserClass *InUserObject, typename FDelegate::template TMethodPtrResolver< UserClass >::FMethodPtr InMethodPtr, FName InFunctionName)
Definition SparseDelegate.h:392
void Remove(const UObject *InObject, FName InFunctionName)
Definition SparseDelegate.h:293
void Broadcast(ParamTypes... Params)
Definition SparseDelegate.h:329