Download

C++ Delegate error

So I’m learning the C++ side of coding and I am working on an inventory system right now. To help get me started, I was doing the video by Reuben for those who are familiar. In the tutorial he has us create a DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnMyInventoryUpdated) that we use to bind to a custom event inside of a widget blueprint. Completed the video tutorial and it all seemed to work fine. I began trying to expand upon the system and I suddenly started getting an error that while running in Debug Mode crashes the editor and throws and exception in VS. However, if I’m running the editor (not debug mode) I receive the following error in the Output Log without a crash:

LogOutputDevice: Error: === Handled ensure: ===
LogOutputDevice: Error: Ensure condition failed: InvocationList[ CurFunctionIndex ] != InDelegate [File:C:\Program Files\Epic Games\UE_4.27\Engine\Source\Runtime\Core\Public\UObject/ScriptDelegates.h] [Line: 556]
LogOutputDevice: Error: Stack:
LogOutputDevice: Error: [Callstack] 0x00007ffe80b22249 UE4Editor-Survival_C-0002.dll!<lambda_504b220f9d24112e82be46ffe98e211b>::operator()() [C:\Program Files\Epic Games\UE_4.27\Engine\Source\Runtime\Core\Public\UObject\ScriptDelegates.h:556]
LogOutputDevice: Error: [Callstack] 0x00007ffe80b140b0 UE4Editor-Survival_C-0002.dll!TBaseDynamicMulticastDelegate<FWeakObjectPtr,void>::__Internal_AddDynamic() [C:\Program Files\Epic Games\UE_4.27\Engine\Source\Runtime\Core\Public\Delegates\DelegateSignatureImpl.inl:1110]
LogOutputDevice: Error: [Callstack] 0x00007ffe80b144a7 UE4Editor-Survival_C-0002.dll!UInventoryScreen::NativeConstruct() [C:\Users\Jesse\Documents\Perforce\SurvivalC\Source\Survival_C\Widgets\InventoryScreen.cpp:18]
LogOutputDevice: Error: [Callstack] 0x00007ffead2ab56a UE4Editor-UMG.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffead2aabf9 UE4Editor-UMG.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffead1c3e98 UE4Editor-UMG.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe80b18631 UE4Editor-Survival_C-0002.dll!ASurvival_CCharacter::OpenInventory() [C:\Users\Jesse\Documents\Perforce\SurvivalC\Source\Survival_C\Survival_CCharacter.cpp:152]
LogOutputDevice: Error: [Callstack] 0x00007ffeb13eed8a UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb141eeee UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb0f06460 UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb0f1763c UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb0f04c2b UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb0f16739 UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb00bc06e UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb12d410e UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb12dd2e4 UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffec1982398 UE4Editor-Core.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffec19827ce UE4Editor-Core.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffec19940bd UE4Editor-Core.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb12f93be UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb12ffaba UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb09e349f UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeb09ee2fc UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeae4914c3 UE4Editor-UnrealEd.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffeaed92ba6 UE4Editor-UnrealEd.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff67ad887a0 UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff67ada0fcc UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff67ada10ba UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff67ada40dd UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff67adb5984 UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff67adb853a UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007fff0bcb7034 KERNEL32.DLL!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007fff0c462651 ntdll.dll!UnknownFunction []

This error occurs when I attempt to open the Inventory Widget where the Blueprint Bind event was. However, there are a few things that are weird with this error. First, when I start the game PIE and open the Inventory Widget and have it display on the screen, I don’t get the error but when I close the Widget and try to open it the second time it stalls for about 5 seconds then I get the error but the game doesn’t crash. I can open the Widget an infinite amount of times after with no issue. I can quit the game PIE and play again and the error never occurs again. However, when I rebuild it after making any changes in VS (as minor as just white space) and re-run the PIE the above incident occurs again. So all this is weird enough but here is the other issue.

This delegate call is really not necessary in the context of the project, Reuben just did it to teach how to use the delegate system to call via blueprints. As such, I deleted the delegate completely and instead just use a straight function call to the widget to do the update that the delegate was originally intended for. In other words, the delegate no longer exists in my project… ANYWHERE. However, the same thing I mention above still occurs. The lines of the error that point to my personal .cpp files is irrelevant as it just points to the method where I call the function to activate the widget and again, there is no delegate call that exists inside my project anymore.

What I’ve done:

  • I’ve deleted all code relating to the delegate and it’s calls
  • I’ve deleted the Binary and Intermediate folders and rebuilt the code
  • I’ve created a new Widget Blueprint to use in place of the original which had the delegate call

Nothing has worked, which is why I’m here. I did see some ideas while googling and it seems that this has been an issue, possibly with the Blueprint VM (Virtual Machine) since at least 4.22? Is there a way I can fix this, especially since I don’t even use the delegate now? Any help would be great, sorry for the super long post but I wanted to give as much detail as possible.

If we go to the line of the crash, ScriptDelegates.h line 556, we find the following block of 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 );
		}
#endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
		InvocationList.Add( InDelegate );

This would seem to indicate that you’re binding the same function multiple times, which apparently is not something you should do.

try right-clicking on your project icon and select “Generate Visual Studio project files”

Correct however, this delegate was only bound to 1 event in 1 blueprint. All I did was call the event, via reference, to execute the delegate. The Bind was never called on more than 1 event at any point.

Also, as I noted, I have completely removed any/all references to the delegate - it no longer exists anywhere (visible) in my project but it seems there may be something hidden that I don’t see which is still driving this error to occur. I’m going to try rebuilding solution files as @ugmoe suggested and see if that works.

Thank you for assisting, it’s much appreciated!

Unfortunately this did not work. The error still persists

It seems like the delegate is still referenced somewhere. Did you check your blueprint as well as the cpp?

Yeah, the only thing inside the blueprint was a single ‘Bind To’ node that attached to a custom event. I deleted that as well as the custom event. I even went as far as to rebuild the blueprint from the ground up hoping to remove any hidden references to it but that didn’t work either.

Where exactly are you binding the event in your widget blueprint? And what UPROPERTY specifiers does the delegate have in your native class? Did you try to unbind the delegate in the widget blueprint destruct event?

With the debugger attached you could also try to figure out where else the delegate is modified by setting a data-breakpoint on it.

The ensure and ensureMsgf macros are written in such a way that they will remember whether they have been triggered. If they were, they ignore the error silently. See https://github.com/EpicGames/UnrealEngine/blob/d94b38ae3446da52224bedd2568c078f828b4039/Engine/Source/Runtime/Core/Public/Misc/AssertionMacros.h#L326
The ensureAlways and ensureAlwaysMsgf variants of the macros would continue to log the error each time it occurs. So in your case the error may simply be suppressed an infinite amount of times after it appeared for the first time. The stall is probably caused since the engine determines the callstack for you which can be quite slow.

The bind was originally set in the widget’s Construct and no I never thought of Destructing it. I can’t attempt to destruct it now because the delegate and it’s (visible) references are all gone. I would have to reconstruct the situation in order to do that.

If these errors are being logged and kept somewhere because of these macro’s, where can I delete the log so they don’t recognize they’ve ever been triggered and therefore not trigger anymore? That link you sent was dead, 404 error.

Thanks for you help!

The link requires you to be logged into github and you’ll need to have access to the Unreal Engine source code (by linking both accounts). The core functionality I was referring to inside the macro is this

			if ((!bExecuted || Always) && FPlatformMisc::IsEnsureAllowed()) \
			{ \
				bExecuted = true; \
				FDebug::OptionallyLogFormattedEnsureMessageReturningFalse(true, #InExpression, __FILE__, __LINE__, ##__VA_ARGS__); \
				...

You would need to modify and then rebuild the engine from source to be able to change this.

The Construct event has a comment/tooltip that explicitly warns it may be called multiple times. And in a situation where you need something to be called-once-when-created OnInitialized should be used instead. Although I’m not certain this happened in your case nor what the exact circumstances need to be for Construct to be called multiple times. This is from UMG/Public/Blueprint/UserWidget.h

	 * Called after the underlying slate widget is constructed.  Depending on how the slate object is used
	 * this event may be called multiple times due to adding and removing from the hierarchy.
	 * If you need a true called-once-when-created event, use OnInitialized.
	 */
	UFUNCTION(BlueprintImplementableEvent, BlueprintCosmetic, Category="User Interface", meta=( Keywords="Begin Play" ))
	void Construct();

Well thank you everyone for your help and suggestions on this. Being new to C++ isn’t easy trying to understand the foundations of the engine. I’ve discovered what I was doing that was causing the error. Originally in the tutorial by Reuben Ward, everything worked fine with the delegate. As I began to expand upon the system creating my own functionality, it started conflicting with some of the things he did, or more correctly with me not handling the situations properly.

In his tutorial, the inventory widget was created new every time you open the inventory. As I moved forward with my code, I decided to store the initial creation of the widget and iterate on that. In the original tutorial code, in the C++ Construct he had this code for the Close Button:

if (CloseButton)
	{
		CloseButton->OnClicked.AddDynamic(this, &UInventoryScreen::CloseButtonOnClicked);
	}

The issue with this code that was throwing the error is the AddDynamic call and explains why when I initially created the widget, I didn’t get the error but on the second opening of the widget, on the stored original, I would get the error and as @UnrealEverything said, it silently was throwing the error in the background the rest of the time. I’m sure I could have continued using the code if I handled the AddDynamic properly in the coding but instead I have removed this code from the C++ construct and decided to just handle the close button directly in blueprints. I no longer get the error.

Thanks again for the help and support! Great community as always!