定义
#define FUNC_DECLARE_MULTICAST_DELEGATE( MulticastDelegateName, ... ) \
typedef TMulticastDelegate<__VA_ARGS__> MulticastDelegateName;
template <typename... ParamTypes>
class TMulticastDelegate<void, ParamTypes...> : public TBaseMulticastDelegate<void, ParamTypes... >
{
private:
typedef TBaseMulticastDelegate< void, ParamTypes... > Super;
};
多播的功能,基本上基于单播,因为多播只是保存了多个单播而已.
多播实际上是一个TBaseMulticastDelegate的子类, 再来看TBaseMulticastDelegate的定义,只列出部分需要讨论的代码
template <typename... ParamTypes>
class TBaseMulticastDelegate<void, ParamTypes...> : public FMulticastDelegateBase<FWeakObjectPtr>
{
typedef FMulticastDelegateBase<FWeakObjectPtr> Super;
public:
typedef TBaseDelegate< void, ParamTypes... > FDelegate;
typedef IBaseDelegateInstance<void (ParamTypes...)> TDelegateInstanceInterface;
template <typename UserClass, typename... VarTypes>
inline FDelegateHandle AddRaw(UserClass* InUserObject, typename TMemFunPtrType<false, UserClass, void (ParamTypes..., VarTypes...)>::Type InFunc, VarTypes... Vars)
{
return Add(FDelegate::CreateRaw(InUserObject, InFunc, Vars...));
}
FDelegateHandle Add(FDelegate&& InNewDelegate)
{
FDelegateHandle Result;
if (Super::GetDelegateInstanceProtectedHelper(InNewDelegate))
{
Result = AddDelegateInstance(MoveTemp(InNewDelegate));
}
return Result;
}
FDelegateHandle Add(const FDelegate& InNewDelegate)
{
FDelegateHandle Result;
if (Super::GetDelegateInstanceProtectedHelper(InNewDelegate))
{
Result = AddDelegateInstance(FDelegate(InNewDelegate));
}
return Result;
}
FDelegateHandle AddDelegateInstance(FDelegate&& InNewDelegate)
{
return Super::AddInternal(MoveTemp(InNewDelegate));
}
void Broadcast(ParamTypes... Params) const
{
bool NeedsCompaction = false;
Super::LockInvocationList();
{
const TInvocationList& LocalInvocationList = Super::GetInvocationList();
// call bound functions in reverse order, so we ignore any instances that may be added by callees
for (int32 InvocationListIndex = LocalInvocationList.Num() - 1; InvocationListIndex >= 0; --InvocationListIndex)
{
// this down-cast is OK! allows for managing invocation list in the base class without requiring virtual functions
const FDelegate& DelegateBase = (const FDelegate&)LocalInvocationList[InvocationListIndex];
IDelegateInstance* DelegateInstanceInterface = Super::GetDelegateInstanceProtectedHelper(DelegateBase);
if (DelegateInstanceInterface == nullptr || !((TDelegateInstanceInterface*)DelegateInstanceInterface)->ExecuteIfSafe(Params...))
{
NeedsCompaction = true;
}
}
}
Super::UnlockInvocationList();
if (NeedsCompaction)
{
const_cast<TBaseMulticastDelegate*>(this)->CompactInvocationList();
}
}
};
可以看到的是, 类似于AddRaw的方法,跟单播里那些方法都一样,多播只不过是调用了单播的方法,生成一个单播的代理对象而已. 最后都会调用到父类 FMulticastDelegateBase的AddInternal方法.
还有最主要的Broadcast方法, 遍历代理数组,如果执行不成功(ExecuteIfSafe失败), 则标记这个代理数组需要压缩(CompactInvocationList).
再看看FMulticastDelegateBase
template<typename ObjectPtrType>
class FMulticastDelegateBase
{
public:
~FMulticastDelegateBase(){}
void Clear( )
{
for (FDelegateBase& DelegateBaseRef : InvocationList)
{
DelegateBaseRef.Unbind();
}
CompactInvocationList(false);
}
// 检查是否有任何功能绑定到此多播委托.
inline bool IsBound( ) const
{
for (const FDelegateBase& DelegateBaseRef : InvocationList)
{
if (DelegateBaseRef.GetDelegateInstanceProtected())
{
return true;
}
}
return false;
}
inline bool IsBoundToObject( void const* InUserObject ) const
{
for (const FDelegateBase& DelegateBaseRef : InvocationList)
{
IDelegateInstance* DelegateInstance = DelegateBaseRef.GetDelegateInstanceProtected();
if ((DelegateInstance != nullptr) && DelegateInstance->HasSameObject(InUserObject))
{
return true;
}
}
return false;
}
void RemoveAll( const void* InUserObject )
{
if (InvocationListLockCount > 0)
{
bool NeedsCompacted = false;
for (FDelegateBase& DelegateBaseRef : InvocationList)
{
IDelegateInstance* DelegateInstance = DelegateBaseRef.GetDelegateInstanceProtected();
if ((DelegateInstance != nullptr) && DelegateInstance->HasSameObject(InUserObject))
{
// Manually unbind the delegate here so the compaction will find and remove it.
DelegateBaseRef.Unbind();
NeedsCompacted = true;
}
}
// can't compact at the moment, but set out threshold to zero so the next add will do it
if (NeedsCompacted)
{
CompactionThreshold = 0;
}
}
else
{
// compact us while shuffling in later delegates to fill holes
for (int32 InvocationListIndex = 0; InvocationListIndex < InvocationList.Num();)
{
FDelegateBase& DelegateBaseRef = InvocationList[InvocationListIndex];
IDelegateInstance* DelegateInstance = DelegateBaseRef.GetDelegateInstanceProtected();
if (DelegateInstance == nullptr
|| DelegateInstance->HasSameObject(InUserObject)
|| DelegateInstance->IsCompactable())
{
InvocationList.RemoveAtSwap(InvocationListIndex, 1, false);
}
else
{
InvocationListIndex++;
}
}
CompactionThreshold = FMath::Max(2, 2 * InvocationList.Num());
InvocationList.Shrink();
}
}
protected:
inline FMulticastDelegateBase( )
: CompactionThreshold(2)
, InvocationListLockCount(0) { }
protected:
inline FDelegateHandle AddInternal(FDelegateBase&& NewDelegateBaseRef)
{
// compact but obey threshold of when this will trigger
CompactInvocationList(true);
FDelegateHandle Result = NewDelegateBaseRef.GetHandle();
InvocationList.Add(MoveTemp(NewDelegateBaseRef));
return Result;
}
void CompactInvocationList(bool CheckThreshold=false)
{
if (InvocationListLockCount > 0)
{
return;
}
//如果检查阈值,则服从但衰减. 这是为了确保即使很少调用的委托也将最终在Add()中压缩
if (CheckThreshold && --CompactionThreshold > InvocationList.Num())
{
return;
}
int32 OldNumItems = InvocationList.Num();
// 查找任何null或可压缩的内容并将其删除
for (int32 InvocationListIndex = 0; InvocationListIndex < InvocationList.Num();)
{
FDelegateBase& DelegateBaseRef = InvocationList[InvocationListIndex];
IDelegateInstance* DelegateInstance = DelegateBaseRef.GetDelegateInstanceProtected();
if (DelegateInstance == nullptr || DelegateInstance->IsCompactable())
{
InvocationList.RemoveAtSwap(InvocationListIndex);
}
else
{
InvocationListIndex++;
}
}
CompactionThreshold = FMath::Max(2, 2 * InvocationList.Num());
if (OldNumItems > CompactionThreshold)
{
// would be nice to shrink down to threshold, but reserve only grows..?
InvocationList.Shrink();
}
}
inline const TInvocationList& GetInvocationList( ) const
{
return InvocationList;
}
inline void LockInvocationList( ) const
{
++InvocationListLockCount;
}
inline void UnlockInvocationList( ) const
{
--InvocationListLockCount;
}
protected:
static FORCEINLINE IDelegateInstance* GetDelegateInstanceProtectedHelper(const FDelegateBase& Base)
{
return Base.GetDelegateInstanceProtected();
}
private:
/** Holds the collection of delegate instances to invoke. */
TInvocationList InvocationList;
/** Used to determine when a compaction should happen. */
int32 CompactionThreshold;
/** Holds a lock counter for the invocation list. */
mutable int32 InvocationListLockCount;
};
RemoveAll里,因为存在多线程访问的问题,因此会先根据InvocationListLockCount > 0进行判断是否有别的线程正在访问,否则就移除和参数InUserObject相关的代理.
FMulticastDelegateBase里,有个很重要的函数AddInternal, 就是上文提及到的, 所有TBaseMulticastDelegate的Add方法,最后都会调用到AddInternal
inline FDelegateHandle AddInternal(FDelegateBase&& NewDelegateBaseRef)
{
CompactInvocationList(true);
FDelegateHandle Result = NewDelegateBaseRef.GetHandle();
InvocationList.Add(MoveTemp(NewDelegateBaseRef));
return Result;
}
首先会调用CompactInvocationList压缩一次代理数组, 这个方法里最主要的判断就是判断代理类的IsCompacktable()
if (DelegateInstance == nullptr || DelegateInstance->IsCompactable())
{
InvocationList.RemoveAtSwap(InvocationListIndex);
}
查看所有的代理实现类里,目前只有TBaseUFunctionDelegateInstance, TBaseUObjectMethodDelegateInstance和TWeakBaseFunctorDelegateInstance重写了基类IsCompactable方法,只看看基类的实现
virtual bool IsCompactable( ) const
{
return !IsSafeToExecute();
}
可以看到,内部是调用了IsSafeToExecute,IsSafeToExecute在各个子类里,也有不同,但基本都是判断代理类是否合理(Valid).
内部有成员变量TInvocationList InvocationList来保存所有代理类FDelegateBase
typedef TArray<FDelegateBase, FMulticastInvocationListAllocatorType> TInvocationList;
FDelegateBase代理类, 内部保存了具体代理对象的实现,单播里已经说过, 比如我们在Add各种操作的时候,就会在FDelegateBase内部生成这个对象.