Creating a onetime lambda function bind to a delegate

How do I bind a lambda function such that it get’s invoked ONLY once and then unbinds?

I tried this but it doesn’t work:


DECLARE_MULTICAST_DELEGATE(FMyDelegate);

FMyDelegate MyDelegate;

FDelegateHandle DelegateHandle;
DelegateHandle=MyDelegate.AddLambda([this, &DelegateHandle](){

    ...

    bool WasRemoved = MyDelegate.Remove(DelegateHandle); // returns false
});

I something like this possible / feasible or should I look into something else entirely?

You’d have to make the delegate handle a member of ‘this’ instead of a local variable.

You’re capturing a reference to stack data, and when that variable goes out of scope then the reference in your lambda will be invalid.

You may also be able to do a TSharedPtr as a local variable and capture that (by value). Because then the handle won’t go out of scope when the function ends.

2 Likes

Simpler solution since an FDelegateHandle is just an int, drop the & and pass by value.

Nope that does not work I tried it, However @MagForceSeven 's answer works when making the delegate handle a member instead of using a local variable

though I’m trying to figure out how to use TSharedPtr so I can use it as a local variable

making the delegate handle a member works but Im trying to keep my code clean and use a local variable instead

I tried your TSharedPtr solution like this:

	TSharedPtr<FDelegateHandle> DelegateHandle = MakeShared<FDelegateHandle>();

	*DelegateHandle=MyDelegate.AddLambda([this, DelegateHandle](){

		bool WasRemoved = MyDelegate.Remove(*DelegateHandle); // returns true
	});

But I’m fairly new to TSharedPtr Will this cause any memory leaks? Also are there any edge cases where this might not work ?

Indeed, my bad. DelegateHandle has not been initialised at the point it is passed, so a reference or pointer will be required.

Also is this the right way to create a static function to bind it ?

template <typename DelegateType, typename FunctionType>
static void OnetimeMulticastDelegate(DelegateType &Delegate, FunctionType &&Lambda ){

	TSharedPtr<FDelegateHandle> DelegateHandle = MakeShared<FDelegateHandle>();
    
    *DelegateHandle = Delegate.AddLambda([DelegateHandle, &Delegate, Lambda]()
    {
        Lambda();
        
        if (DelegateHandle.IsValid())
             Delegate.Remove(*DelegateHandle);
    });
}


// usage
OnetimeMulticastDelegate(MyDelegate, [](){
   ...
})

No. When the delegate is removed, the lambda will be destructed which will destruct your copy of the shared ptr and the handle it was referencing will be free’d.

Not that come to mind.

That looks like it should be fine. You have to be careful when capturing stuff (like that delegate) by reference but since there’s no way for the Added lambda to be called if the delegate no longer exists you should be fine.

1 Like

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