Using a TMap with values of class AActor

The Problem

For my survival game, I am creating a fairly standard inventory system. This works by having a UInventoryComponent that is a child of UActorComponent. This component stores information about the inventory, using a TArray of AItem. I am having trouble creating the item registry/database, however, which should store a TMap of FString keys for the ID’s and class AItem values. When I try to compile my current code, I get 15 errors, including:


CompilerResultsLog: Info /Users/Shared/UnrealEngine/4.7/Engine/Source/Runtime/Core/Public/Containers/Map.h:852:26: error: no type named 'KeyInitType' in 'TSortableMapBase >'
CompilerResultsLog: Info         typedef typename Super::KeyInitType KeyInitType;
CompilerResultsLog: Info                 ~~~~~~~~~~~~~~~~^~~~~~~~~~~
CompilerResultsLog: Info ../../../../../AidoP/Unreal Projects/OncomingPreAlpha/Source/OncomingPreAlpha/ItemRegistry.h:16:32: note: in instantiation of template class 'TMap >' requested here
CompilerResultsLog: Info     TMap\ Registry;

and

CompilerResultsLog: Info /Users/Shared/UnrealEngine/4.7/Engine/Source/Runtime/Core/Public/Containers/Map.h:853:26: error: no type named 'KeyConstPointerType' in 'TSortableMapBase >'
CompilerResultsLog: Info         typedef typename Super::KeyConstPointerType KeyConstPointerType;
CompilerResultsLog: Info                 ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
CompilerResultsLog: Info /Users/AidoP/Unreal Projects/OncomingPreAlpha/Source/OncomingPreAlpha/ItemRegistry.cpp:10:15: error: exception specification in declaration does not match previous declaration
CompilerResultsLog: Info ItemRegistry::~ItemRegistry() {
CompilerResultsLog: Info               ^
CompilerResultsLog: Info ../../../../../AidoP/Unreal Projects/OncomingPreAlpha/Source/OncomingPreAlpha/ItemRegistry.h:12:2: note: previous declaration is here
CompilerResultsLog: Info         ~ItemRegistry();
CompilerResultsLog: Info         ^
CompilerResultsLog: Info /Users/AidoP/Unreal Projects/OncomingPreAlpha/Source/OncomingPreAlpha/ItemRegistry.cpp:14:20: error: return type of out-of-line definition of 'ItemRegistry::AddToRegistry' differs from that in the declaration
CompilerResultsLog: Info bool ItemRegistry::AddToRegistry(class AItem Item, FString ID){
CompilerResultsLog: Info                    ^
CompilerResultsLog: Info ../../../../../AidoP/Unreal Projects/OncomingPreAlpha/Source/OncomingPreAlpha/ItemRegistry.h:14:10: note: previous declaration is here
CompilerResultsLog: Info     void AddToRegistry(class AItem Item, FString ID);
CompilerResultsLog: Info          ^
CompilerResultsLog: Info /Users/AidoP/Unreal Projects/OncomingPreAlpha/Source/OncomingPreAlpha/ItemRegistry.cpp:14:46: error: variable has incomplete type 'class AItem'
CompilerResultsLog: Info bool ItemRegistry::AddToRegistry(class AItem Item, FString ID){
CompilerResultsLog: Info                                              ^
CompilerResultsLog: Info ../../../../../AidoP/Unreal Projects/OncomingPreAlpha/Source/OncomingPreAlpha/ItemRegistry.h:14:30: note: forward declaration of 'AItem'
CompilerResultsLog: Info     void AddToRegistry(class AItem Item, FString ID);
CompilerResultsLog: Info                              ^

Which is caused by the following code:

.h



	#pragma once

	/**
	 * 
	 */
	 class ONCOMINGPREALPHA_API ItemRegistry {
	   
	 public:
		ItemRegistry();
		 ~ItemRegistry();
  		  
    	 void AddToRegistry(class AItem Item, FString ID);
    
   	 TMap Registry;
	};

.cpp



	#include "OncomingPreAlpha.h"
	#include "ItemRegistry.h"

	 ItemRegistry::ItemRegistry() {
    	
	}
	
	 ItemRegistry::~ItemRegistry() {
    	
	}
	
	 bool ItemRegistry::AddToRegistry(class AItem Item, FString ID){
    	 	if(Registry.contains(ID)) {
       			 return false;
    		}
    
	 	 Registry.Add(ID, Item);
    
   		 return true;
	}

So what can I do to use ‘class AItem’ as the value in the TMap.

Thanks for helping.

Sorry about all those stupid errors, I’m having a bad day.

It did fix my errors, but if you don’t mind, could you give a quick explanation of why to use pointers in the TMap? I am a Java/C# developer and pointers have been annoying to get the hang of.

Thanks for the reply!

There are a lot of things wrong with this code. Your declaration of AddToRegistry is different than its definition (you return “void” instead of “bool” according the the header). “Registry.contains(ID)” needs a capital C. You’re passing objects instead of pointers (AItem should be AItem*). Your TMap should use a pointer instead of object as well (again AItem*). If these don’t fix your issues, then edit your question to include the errors that happen after all these other issues have been fixed.

You know the difference between a struct and a class in C#? That’s sort-of the difference between a pointer and a object in C++. Basically, if you don’t declare a variable a pointer, then you are asking for the object to be allocated where that variable is.

In Java, everything is basically a pointer, and Java manages the life of the object based on if any pointers (references in Java) are pointing to (referencing) that object. In UE4, Epic has created a similar garbage collection system for UObjects (which AActors derive from), and basically you have to use pointers and ConstructObject (or SpawnActor for Actors) in order to have your new object take part in this system (which Java and C# basically do by default). FString, or anything that starts with F, is not managed by UObject Garbage Collection, hence it starts the F and not U or A (these are here for readability and don’t actually affect behavior).

Anyway, a TMap of pointers will only “reference” the object, not actually hold the memory of the object. If you have a Player object somewhere in the world, there should only be 1 memory allocation of that Player, but then tons of pointers (references) for every place you want to use that Player. If TMap took an object and not its pointer, then that would be a copy of the object and not the object you actually wanted to work with. Furthermore, UE4 might have measures in place to prevent you from not providing a pointer for any UObject derived class, hence the weird compiler errors.

One final thing: Since this isn’t Java or C# and doesn’t depend on object reference counts to maintain the life of the object, and object can (and will) be deleted regardless if something is pointing to it. This means at some point your TMap could have a pointer to an object that no longer exists. In your UObject classes you can avoid this by putting UPROPERTY() above the pointer. This will tell UE4 that this pointer is a weak reference and that it needs to be nulled out when the object is deleted. As for a TMap with pointers, I’m not sure if putting UPROPERTY() above the TMap in your class will do this (it will only apply “UPROPERTY” stuff to the map itself). This is where a TWeakObjectPtr comes into play (I think). So basically, you can have a TMap> that will have its TWeakObjectPtrs automatically invalidated when the AItem was destroyed by the engine elsewhere. I don’t think you really need this right now, but note that I didn’t put AItem* because the TWeakObjectPtr definition will make the variable a pointer behind the scenes.

Thanks again for all the help!

Sorry to bother you, but when calling the AddToRegistry() function, I was getting an expected expression error. I’m not sure what I changed, but when I tried to compile, the editor crashed, and keeps crashing now.

My .cpp is


	
	#include "OncomingPreAlpha.h"
	#include "ItemRegistry.h"

	 ItemRegistry::ItemRegistry() {
		 UWorld* world = GetWorld();
		 if (world) {
	 	 	 AItem* spawned = (AItem*) world->SpawnActor(ANULLItem::StaticClass());
        
        		 AddToRegistry(spawned, "NULL");
    		}
	}
	
	 ItemRegistry::~ItemRegistry() {
 	   
	}
	
	 bool ItemRegistry::AddToRegistry(class AItem* Item, FString ID) {
    	 	 if(Registry.Contains(ID)) {
        	 	 return false;
    		}

	 	 Registry.Add(ID, Item);
    		
   		 return true;
	}

and my .h is


	 
	 #include "Item/NULLItem.h"
	 #pragma once

	 class ONCOMINGPREALPHA_API ItemRegistry : public UObject {
    
	 public:
	 	 ItemRegistry();
	 	 ~ItemRegistry();
	 
	 	 bool AddToRegistry(class AItem* Item, FString ID);
	 
	 	 	 TMap Registry;
	 	 };
	 

Wait, so is the UE4 editor crashing or VS? Is the code actually compiling? What is the error you’re given when it crashes? What’s the callstack?

The editor is crashing.

‘Exception was “SIGSEGV: invalid attempt to access memory at address 0x3”’

It also would be useful to mention I have a mac.

The callstack was to big to post in the comments but I put it on pastebin.

I’m not sure I can help, but it’s crashing in the construction of a default object. Either your InventoryComponent or your Item actor. So you must have some bad logic in there? If its trying to access memory at address 0x3, that sounds like you have a bad pointer. Maybe you have an object somewhere that should be a pointer? Like maybe you have AItem in UInventoryComponent instead of AItem*?

I had a subclass of AItem (AClothingItem) where I had objects rather than pointers, thanks for pointing that out. So I have changed them to pointers, but I can’t recompile now. I tried using Xcode’s compiler, but it is still crashing.

What I mean is that after compiling that older code, the editor started crashing, but now I have fixed what was causing the crashes in the uncompiled code. However, since I can’t open up the editor, I can’t compile the fixed code to stop the crashes.

It is still the same error and callstack, I just worded my last comment wrong.

Its confusing when you say you cant recompile but you are still crashing. If you can’t compile then you cant crash because. If you are crashing, then you’ve already managed to compile. They are very different things.

In either case, I need to see what the error is or the callstack.

You’re not compiling the code from XCode? I don’t know much about mac, but you probably shouldn’t be depending on UE4 to compile your code? If you don’t know how to do that (but really you shouldn’t do this), delete your Binaries folder and then when you open the project that will force a recompile.

(But I stress again, you should be compiling from your code IDE, not in engine. You actually have to compile from outside the editor for many header file changes to properly work)

No, I thought it was required to compile through the editor.

But I’ve managed to get it to work now by recompiling through the IDE and by deleting the binaries folder. Thanks for helping, it’s really appreciated.