Crash with TMap < FString, std::function < ...> >

UE4 (tested on both 4.10.4 and 4.11.0) crashes on closing if the active GameInstance object has the following field

TMap<FString, std::function<void(int)> > Callbacks;

filled with several entries (to have the crash you have to insert at least 5-8 items), like:

Callbacks.Add(TEXT("1"), [this](int i) { });
// ...repeat several times...

[In attachment you can find a test project showing the problem.][1]

The stack trace is:

Access violation - code c0000005 (first/second chance not available)

UE4Editor_TMap11!TSparseArray<TSetElement<TPair<FString,std::function<void __cdecl(int)> > >,TSparseArrayAllocator<FDefaultAllocator,FDefaultBitArrayAllocator> >::Empty() [c:\program files\unreal engine\4.11\engine\source\runtime\core\public\containers\sparsearray.h:222]
UE4Editor_TMap11!UMyGameInstance::~UMyGameInstance()
UE4Editor_TMap11!UMyGameInstance::`vector deleting destructor'()
UE4Editor_CoreUObject!IncrementalPurgeGarbage() [d:\buildfarm\buildmachine_++ue4+release-4.11\engine\source\runtime\coreuobject\private\uobject\garbagecollection.cpp:1041]
UE4Editor_CoreUObject!CollectGarbageInternal() [d:\buildfarm\buildmachine_++ue4+release-4.11\engine\source\runtime\coreuobject\private\uobject\garbagecollection.cpp:1319]
UE4Editor_CoreUObject!CollectGarbage() [d:\buildfarm\buildmachine_++ue4+release-4.11\engine\source\runtime\coreuobject\private\uobject\garbagecollection.cpp:1336]
UE4Editor_UnrealEd!UEditorEngine::EndPlayMap() [d:\buildfarm\buildmachine_++ue4+release-4.11\engine\source\editor\unrealed\private\playlevel.cpp:375]
UE4Editor_UnrealEd!UEditorEngine::Tick() [d:\buildfarm\buildmachine_++ue4+release-4.11\engine\source\editor\unrealed\private\editorengine.cpp:977]
UE4Editor_UnrealEd!UUnrealEdEngine::Tick() [d:\buildfarm\buildmachine_++ue4+release-4.11\engine\source\editor\unrealed\private\unrealedengine.cpp:370]
UE4Editor!FEngineLoop::Tick() [d:\buildfarm\buildmachine_++ue4+release-4.11\engine\source\runtime\launch\private\launchengineloop.cpp:2643]
UE4Editor!GuardedMain() [d:\buildfarm\buildmachine_++ue4+release-4.11\engine\source\runtime\launch\private\launch.cpp:142]
UE4Editor!GuardedMainWrapper() [d:\buildfarm\buildmachine_++ue4+release-4.11\engine\source\runtime\launch\private\windows\launchwindows.cpp:126]
UE4Editor!WinMain() [d:\buildfarm\buildmachine_++ue4+release-4.11\engine\source\runtime\launch\private\windows\launchwindows.cpp:200]
UE4Editor!__scrt_common_main_seh() [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:264]
kernel32
ntdll

The offending UE4 code in TSparseArray (method Empty(), row 222):

84904-sparsearray-empty-222.png

FYI, this the custom GameInstance class used:

// .H FILE
#pragma once

#include "Engine/GameInstance.h"
#include <functional>
#include "MyGameInstance.generated.h"

// Settings > Project Settings > Maps & Modes > Game Instance Class
UCLASS()
class TMAP11_API UMyGameInstance : public UGameInstance
{
	GENERATED_BODY()

public:
	virtual void Init() override;
	
private:
	typedef std::function<void(int)> CallbackType;
	TMap<FString, CallbackType> Callbacks;
};



// .CPP FILE
#include "TMap11.h"
#include "MyGameInstance.h"

void UMyGameInstance::Init()
{
	Callbacks.Add(TEXT("1"), [this](int i) { });
	Callbacks.Add(TEXT("2"), [this](int i) { });
	Callbacks.Add(TEXT("3"), [this](int i) { });
	Callbacks.Add(TEXT("4"), [this](int i) { });
	Callbacks.Add(TEXT("5"), [this](int i) { });
	Callbacks.Add(TEXT("6"), [this](int i) { });
}

Unexpectedly I didn’t find a way to insert a “<” character in the title, I would be glad if someone can fix it :wink:

Hi Kafu,

Storing std::functions in UE containers will not work. Please see this other thread for more details: TMap value type limitations - Programming & Scripting - Unreal Engine Forums

Since that original thread, however, we have implemented our own TFunction instead, which is compatible with our containers. If you replace std::function with TFunction in the code above, it should ‘just work’.

Steve

Hi Steve, thanks. I confirm that TFunction ‘just worked’!

BTW, It’s a very tricky problem to catch, maybe a static assert or some notes in the documentation could help other devs too. Thanks for the support!