Crash with TMap

Hi! I have TMap defined like this:


		UPROPERTY()
		TMap<EBaseStats, int32> statsBase;

Later in the code, I do:


	this->statsBase.Empty();
	this->statsBase.Reserve(3);
	for (int32 s = 0; s <= 3 s++)
	{
		this->statsBase.Add((EBaseStats)s, 0);
	}

All runs fine when I hit play.
Then I hit stop. Play again;

Crash is something about not being able to allocate memory properly to the array.

Even though I have TMap marked with UPROPERTY(), do I still need to manually clean up after it, when I stop game from running? Or something else happening here and I am on the wrong track?

Have your try to use something like:



//Empty() takes an optional slack value which can be used to optimize the case when you are about to repopulate the map with a given number of elements
statsBase.Empty(3)
for (int32 s = 0; s < 3 s++)
{
      this->statsBase.Add((EBaseStats)s, 0);
}


Note: When you using Reserve function you reserve 3 elements, but your 4 for loop add 4 items with the <= condition.

I hope that help you :slight_smile:

I’m not sure if it was ever fixed but TMap had horrendous performance. I would make a struct with your key value pair and use a regular tarray. someone correct me if im wrong.

From what i remember i didn’t think TMaps could be UPROPERTY’s

Thanks for the replies! I agree with the points listed here, but they do not explain the crash. Empty() should not care about reserve size, and because it happens between game runs, I assume that I am triggering some nullpointer or other similar issue.

I was reading through all the docs and forums again, and yet can not come to some guarantee conclusion. Can someone clarify, when I have TMap marked as UPROPERTY’s, do I need to manually clean it up (empty), or its managed by engine? Its not that I am too lazy to do it, I just want to know, where that crash comes from.

Some says they can, some say that not. From what I understand, it was added is some version between 4.9 - 4.13, but without ability to be in blueprints.

If something is marked as a UPROPERTY, it’s generally best to let the engine manage clean up (IIRC). If you’re seeing the problem when you hit “Play” a second time, you might want to check out any code you have in BeginPlay to make sure you aren’t manually destroying objects and then trying to re-use them, etc.

Got it, thank you!

I cheked, I am not doing anything else aside from this assigment. But, if I change TMap to TArray, crash is gone. I suspect this is some kind of a bug then. I have no other explanation under this circumstances at least.

Have you tried just calling Reset on the Map? That will erase the contents but keep the allocated memory. Otherwise you should make a post on the Answer Hub so that the Devs can investigate and fix the bug.

I did. I think go on investigating more, isolating the code, looking for the issue. I feel this is my mistake somewhere. Thank you for the replies, I am positive, what I have to do now - look for teh issue inside my code.

EDIT: Figured this out; I had a pointer to my UActorComponent, unmanaged by Unreal by my own design. I forgot to nullptr it on BeginDestroy, and that caused all the problems. I wonder , if there is some universal solution to scan code for problems like that. In any case, seem to fixed now.

Hm it’s hashmap. Last timeI profiled it had lookup performance within 0.01ms, and most likely lower, since 0.01 is smallest number you can get from stats system (or it was last time I checked). I guess that insert/delete are słów, and when there are hash collsions.

Hash table lookup performance on just about any key should be way, way, way faster than .01ms. Assuming the map is setup somewhat correctly with buckets and all that… It’s the best all-around lookup container IMO, although raw arrays will be faster when there’s only a few elements.

Back to OP, the dangling UActorComponent problem is solved by making it a UPROPERTY(), assuming it is a member of some class. If its not, you can always use smart pointers, although I can’t remember if they work on UObjects. My gut tells me no.
I believe the UPROPERTY() does some magic so that when the object gets deleted, it nulls out all references (haven’t looked into the exact mechanism for this though, although could just be smart pointers under the hood that UHT creates?)

So I think you were using the TMap correctly, since it owned all the memory inside it, Empty() can’t possibly have deleted anything external.

Good to know you can mark TMap with UPROPERTY() in newer versions!