Exception when trying to bind a UFUNCTION with AddDynamic to a Delegate

Hello.
Added UDP Component plugin (from here: GitHub - getnamo/UDP-Unreal: Convenience UDP wrapper for the Unreal Engine.) to my project and now im trying to bind a UFUNCTION HandleReceivedBytes (from my pawn class) to a Delegate event OnReceivedBytes (from this plugin).
.h file:

class UAVCESIUM_API AUavSimPawn : public APawn
{
	GENERATED_BODY()

public:
	AUavSimPawn();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	// Utilities
	UFUNCTION()
	void HandleReceivedBytes(const TArray<uint8>& Bytes, const FString& IPAddress, const int32& Port);

	// Components
	UPROPERTY(VisibleAnywhere)
	class UUDPComponent* UdpComp;

.cpp file:


AUavSimPawn::AUavSimPawn()
{
	UdpComp = CreateDefaultSubobject<UUDPComponent>(TEXT("UdpComponent"));
	UdpComp->Settings.bShouldAutoOpenReceive = false;
	UdpComp->Settings.bShouldAutoOpenSend = false;
	UdpComp->OpenReceiveSocket(TEXT("127.0.0.1"), 5228);
}

void AUavSimPawn::BeginPlay()
{
	Super::BeginPlay();

	// Binding a function for handling OnReceivedBytes delegate
	// Exception happens here:
	UdpComp->OnReceivedBytes.AddDynamic(this, &AUavSimPawn::HandleReceivedBytes);

The excpetion happens in “ScriptDelegates.h” in this line (556):

(void)ensure( InvocationList[ CurFunctionIndex ] != InDelegate )

from this code:

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
		// Verify same function isn't already bound
		const int32 NumFunctions = InvocationList.Num();
		for( int32 CurFunctionIndex = 0; CurFunctionIndex < NumFunctions; ++CurFunctionIndex )
		{
			(void)ensure( InvocationList[ CurFunctionIndex ] != InDelegate ); // HERE
		}
#endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
		InvocationList.Add( InDelegate );
	}

I figured out that this exception means that the function is already is in invokation list. Also i came to that point with debugger and yes, this function (“HandleReceivedBytes”) could be seen here before the function is actually added.
But i couldn’t find out why does it happens - i only have one call of function “AddDynamic” (put a breakpoint on it and it happened only once).

P.s. Also guess i should mention this one: if I put “AddDynamic” line in ctor of my Pawn class then the exception doesn’t appear but when i play it creates another copy of my Pawn and binds that HandleReceivedBytes method to it instead of an instance of my Pawn which is on a level.

upd: when using AddUniqueDynamic instead of AddDynamic the error does not appear but the function bound to delegate does not invokes. I noticed something strange. I added those two lines to check if OnReceivedBytes delegate already has any bound functions and with debugger I found out that it really has one - it’s my HandleReceivedBytes. I can’t understand how it could be already bound if I’m binding it after this check:

void AUavSimPawn::BeginPlay()
{
    Super::BeginPlay();

    if (UdpComp->OnReceivedBytes.IsBound())
        UdpComp->OnReceivedBytes.Clear();
    //UdpComp->OnReceivedBytes.AddDynamic(this, &AUavSimPawn::HandleReceivedBytes);
    UdpComp->OnReceivedBytes.AddUniqueDynamic(this, &AUavSimPawn::HandleReceivedBytes); // Also tried AddUniqueDynamic just for overcoming the exception
    
}

binding to a delegate should definitely not be done in the constructor of any object. It should be done on an instance of a Pawn once when required, usually during BeginPlay. The constructor is only meant to set up the class itself without accessing other objects (can be dangerous). In UE there is another reason, read this:

What is CDO? - #2 by anonymous_user_9f4576f5

This should live on BeginPlay as well:

UdpComp->OpenReceiveSocket(TEXT("127.0.0.1"), 5228);

It’s hard to tell what is going on without seeing an entire call stack. If you put a breakpoint before the moment it would assert, can you find new information in previous steps listed in the callstack?

binding to a delegate should definitely not be done in the constructor of any object.

I did not bind to a delegate in a constructor, I put it in BeginPlay. Put thanks for a useful link!

This should live on BeginPlay as well:

UdpComp->OpenReceiveSocket(TEXT("127.0.0.1"), 5228);

Yep. It helped. Now I am able to listen to that socket.

If you put a breakpoint before the moment it would assert, can you find new information in previous steps listed in the callstack?

Here is my call stack (I didn’t thinked out a better idea then just copy name of calls and put them in a list below):

  • This is top of stack where the exception happens: UE4Editor-Project.dll!TMulticastScriptDelegate::AddInternal::__l4::<lambda_4de4e9647c80ad9f1ebd5845fb39e2ab>::operator()() Line 556
  • [Embedded frame] UE4Editor-Project.dll!TMulticastScriptDelegate::AddInternal(const TScriptDelegate &) Line 556
  • [Embedded frame] UE4Editor-Project.dll!TMulticastScriptDelegate::Add(const TScriptDelegate &) Line 327
  • UE4Editor-Project.dll!TBaseDynamicMulticastDelegate<FWeakObjectPtr,void,TArray<unsigned char,TSizedDefaultAllocator<32>> const &,FString const &,int const &>::__Internal_AddDynamic(AUavSimPawn * InUserObject, void(AUavSimPawn::*)(const TArray<unsigned char,TSizedDefaultAllocator<32>> &, const FString &, const int &) InMethodPtr, FName InFunctionName) Line 1110
  • UE4Editor-Project.dll!AUavSimPawn::BeginPlay() Line 88

By some reasons there is still bounded function. Also I noticed one thing: even if I remove line with AddDynamic or AddUniqueDynamic unreal still binds HandleReceivedBytes to a delegate somehow…
I tried cleaning and rebuilding the whole project but it didn’t change anything. Then I renamed my function which I’m trying to bind to another name and it suddenly works as expected: if this function is not bound to a delegate - nothing happens. And if I explicitly bind it with AddDynamic then it successfully binds and the socket works.

I thought that inside the plugin there could be some default function with name HandleReceivedBytes but there aren’t one.

Now everything works tho, but I still can’t understand how there could be already a bound function and how it could be bounded without using AddDynamic.

I have a feeling that that happens using an ‘old’ blueprint asset deriving from the AUavSimPawn? Blueprints can corrupt like that. If your c++ is fine, it shouldn’t happen if your method name wasn’t stored somewhere in a way that conflicts with your current C++.

You could test making a new blueprint asset deriving from the class using the old function name, if that works you are most likely looking at a corrupt asset.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.