Here is the next iteration of all this and at the moment I am not facing any errors. In prev comment I was wrong. The errors there comes not from global changes of memory addresses, but rather from tricky memory allocation of TMap container. So, when I move to simple c++ std::map class, those strange pointer mistakes go away
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include <map>
#include "OwnerMulticasterComponentBase.generated.h"
class UActorComponent;
DECLARE_MULTICAST_DELEGATE(FOnComponentEndPlayEvent);
UINTERFACE(MinimalAPI)
class UOwnerMulticasterComponentBase : public UInterface {
GENERATED_BODY()
};
class REBELHERO_API IOwnerMulticasterComponentBase {
GENERATED_BODY()
protected:
FCriticalSection Locker;
template<typename T>
std::map<IOwnerMulticasterComponentBase*, T*>& GetMapping_TOwner() {
static std::map<IOwnerMulticasterComponentBase*, T*> ownerMapping;
return ownerMapping;
}
template<typename T>
std::map<IOwnerMulticasterComponentBase*, FDelegateHandle>& GetMapping_Callback() {
static std::map<IOwnerMulticasterComponentBase*, FDelegateHandle> callbackMapping;
return callbackMapping;
}
template<typename T>
void OnComponentEndPlayCallback() {
FScopeLock Lock(&Locker);
auto& ownerMapping = GetMapping_TOwner<T>();
ownerMapping.erase(this);
auto& callbackMapping = GetMapping_Callback<T>();
OnComponentEndPlay.Remove(callbackMapping[this]);
callbackMapping.erase(this);
}
public:
FOnComponentEndPlayEvent OnComponentEndPlay;
virtual UActorComponent* GetSelfAsActorComponent() { return nullptr; };
template<typename T>
T* GetOwnerAs() {
FScopeLock Lock(&Locker);
auto& ownerMapping = GetMapping_TOwner<T>();
auto It = ownerMapping.find(this);
if (It != ownerMapping.end()) return It->second;
T* castedOwner = nullptr;
if (auto component = GetSelfAsActorComponent()) {
castedOwner = Cast<T>(component->GetOwner());
}
ownerMapping.emplace(this, castedOwner);
auto& callbackMapping = GetMapping_Callback<T>();
callbackMapping.emplace(this, OnComponentEndPlay.AddRaw(this, &IOwnerMulticasterComponentBase::OnComponentEndPlayCallback<T>));
return castedOwner;
}
};