Using lambda for delegate handing for managing session in OnlineSusystem

I’ve create a manager class deriving from Game Instance Subsystem to provide access to creating, finding and joining sessions using the Online Subsystem.
However I discovered that the delegates that the OS interface provides don’t seem to be unregistered when using lambdas and the respective delegates rather than delegate handles.

Here’s the code:

OnlineSubsystem = IOnlineSubsystem::Get();
const IOnlineSessionPtr SessionPtr = OnlineSubsystem->GetSessionInterface();

SessionPtr->OnCreateSessionCompleteDelegates.AddLambda([&](FName SessionName, bool Successful)
{
    // class custom multicast delegate
	OnCreateSessionCompleted.Broadcast(Successful);

	if (const IOnlineSessionPtr SessionPtr = 
         OnlineSubsystem->GetSessionInterface())
	{
         // piece of code that seems not to unregister the delegate
	     SessionPtr->ClearOnCreateSessionCompleteDelegates(this);
	}
});

The delegate is fired correctly when session is created, but if the function is called again it will fire as many times as it has been called. However if I use delegate handles and clear using delegate handles everything works as expected.

SessionPtr-> ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle);

I cannot seem to find this function anywhere in any of the engine versions, but I’m gonna assume the void* Object parameter it takes is meant to be used to clear all delegates bound to that specific Object.

Problem is, lambdas are not bound to a specific object. Even if you capture this via the capture mechanism, code has no way to retrieve it for comparison.

You need to use object-bound delegate method. AddStatic and AddLambda will not work. AddWeakLambda might do the job.

Thanks for the clear explanation and solution as it worked. I saw also that many examples use a delegate handle to clear bound objects. Do you mind explaining what are the advantages of the delegate_handle compared to the typical delegate ? Since the sessions interface provides both types.

Well in this case handles are useful if you want to bind (and later clear) to a non-object bound function, such as a static or a regular lambda.

In general, handles can also be useful for several use cases :

  • you can bind a multicast delegate multiple times within the same object, and then you only want to clear one of them.

  • you can use IsValid() to check is a specific delegate handle is bound or not.

  • you can use Reset() to clear a delegate handle. Most of the time objects do not provide a “ClearAllDelegates” function like you are using here, so storing all delegate handles into an array gives you an easy way to clear all of them at some point.

1 Like