Pointer reference changing after initialization.

Hello every one… I am facing a really horrible bug… Been working on it all night (6am now) but still cannot find a way to solve it.

Basically I got a array having structure pointers that are pointing to another array having values.


FItemStruct TempStruct;
		TempStruct.Fok = 11;
		for (int8 i = 0; i < Storage.Rows.Num(); i++)
		{
			for (int8 j = 0; j < Storage.Rows*.Columns.Num(); j++)
			{
				StorageArray.Add(TempStruct);
				Storage.Rows*.Columns[j].ItemStruct = &StorageArray[StorageArray.Num() - 1];


				GEngine->AddOnScreenDebugMessage(-1, 15, FColor::Cyan,
					FString::FromInt(i) + " " +
					FString::FromInt(j) + "    " +
					FString::FromInt(Storage.Rows*.Columns[j].ItemStruct->Fok));
			}
		}

This is how I am initializing both the Main array and the array containing the references. I neglected 1 part that the reference array is a 2d array… But it shouldn’t be the problem here.

The StorageArray is the main storage location while the Storage.Rows*.Columns[j].ItemStruct contains the pointer to the location

The I am initializing a value just for testing


TempStruct.Fok = 11;

Here in the Screen message, everything appears fine…

Then when I check the value when Ticking, a few values appeared to have changed. Only if i check them through the storage pointer.

While the actual values in the variable array doesn’t change
13140b6b0b9c00a7472df952121c6e912d426647.jpeg

The Tick function


	for (int8 i = 0; i < Storage.Rows.Num(); i++)
	{
		for (int8 j = 0; j < Storage.Rows*.Columns.Num(); j++)
		{
			if (Storage.Rows*.Columns[j].ItemStruct)
			{
				GEngine->AddOnScreenDebugMessage(-1, DeltaSeconds, FColor::Green,
					FString::FromInt(i) + " " +
					FString::FromInt(j) + "    " +
					FString::FromInt(Storage.Rows*.Columns[j].ItemStruct->Fok));
			}
		}
	}
	for (int8 k = 0; k < StorageBase.Num(); k++)
	{
		GEngine->AddOnScreenDebugMessage(-1, DeltaSeconds, FColor::Blue, FString::FromInt(StorageBase[k].Fok));
	}

Also one very important thing is my pointer is not a** smart pointer** but a naked pointer.


	FItemStruct* ItemStruct;

I cant have UPROPERTY() structure pointers

I think you are storing a pointer to a struct in an array?

If so when the array resizes your pointer is going to end up pointing at the old location of the entries in the array while the array itself will have allocated new (larger) memory to hold the increased data.

There is an array type that does not reallocate memory called TIndirectArray, but with your multiple dimensions it might get a bit awkward.

Alternatively instead of having a TArray of your struct type you could have a TAaray of TSharedPtr of your struct type and then your reference would also be a TSharedPtr so that they always point to the same memory

Instead of storing pointers to array entries in another array, could you just store the indices?

I tried TArray ended up having the same problem… I think I should switch from pointer to indices instead.

I actually have a similar thing going for our inventory system. Presentation logic has an array of structs containing necessary data to interact with presented items. Then, when adding an item, I also bind the delegates I need by passing a pointer to those structs as payload. The observed issue was similar – after the array was modified, the array’s contents shifted around and the pointers became invalid.

Using your own example:


FItemStruct TempStruct;
StorageArray.Add(TempStruct);
Storage.Rows*.Columns[j].ItemStruct = **&StorageArray[StorageArray.Num() - 1]**; // this part is what can't work -- the pointer will change

The cleanest and simplest solution, as Marc suggests, is to use an IndirectArray. All you have to do then is to change your array’s initialization and referencing from the above to:

To:


FItemStruct* TempStruct = new FItemStruct();
StorageArray.Add(TempStruct);
Storage.Rows*.Columns[j].ItemStruct = TempStruct;

Storing indices instead of pointers feels like it would be a tedious workaround as you would then have to do maintenance on your dependent array to update indices whenever you change the base array.

I did a work around involving 2 things…

First, I have a structure containing the 2d Array… I add a pointer to the 1D array to it.


	TArray<FItemStruct>* StorageBasePtr;

Then added a function to execute while initializing the array


bool InitializeArray(TArray<FItemStruct> &StorageArray)
	{
		if (Rows.Num() > 0 && Rows[0].Columns.Num() > 0)
		{
			StorageBasePtr = &StorageArray;
			FItemStruct TempStruct;
			TempStruct.ItemClass = nullptr;
			for (int8 i = 0; i < Rows.Num(); i++)
			{
				for (int8 j = 0; j < Rows*.Columns.Num(); j++)
				{
					StorageArray.Add(TempStruct);
					Rows*.Columns[j].Index = (StorageArray.Num() - 1);
				}
			}
			return true;
		}
		return false;
	}

So it individual elements in the 2d array store the index and the structure as a whole stores a pointer to the 1D array…

Solved most of the problems. I i doubt if using a naked pointer cause any problems



TArray<FItemStruct>* StorageBasePtr;

I tried using a TSharedPtr and UE4 crashes when existing the game/

I fail to see why you would need that pointer to the StorageBase array.

In fact, I don’t see why you even need a separate StorageBase array.

Your initial post made it sound like you’d keep “empty” entries as null in the 2D array, whereas you’d point to an entry in your storage array for the 2D entries that do contain something. In that context, using a separate storage array using TIndirectArray/TSharedPtr/index approaches makes sense.

But based on that last snippet, it seems like you’re initializing every single entry in the 2D array. Why not make your life simpler and just store directly in the 2D array?

Well wish I could… :frowning: I had done something similar but the problem is “replication”…

1D arrays replicate good. Only send the thing that has been changed. To contain a 2d array, i have to store “Arrays” inside a structure. So, which a single unit inside a structure is changed, the whole structure tries to get replicated.

So if my 2D array is present inside a single structure. If 1 element of the array gets changed everything needs to sent over network(the whole 2D array).

The TSubItemClass that have been assigned nullptr don’t contain any items. I detect that in the slate and show empty icon. The array size don’t change after the initalization command takes place. When item change I change the value of the TSubItemClass.

Along with it, the FItemStruct contain a few other variable to show how many item stacks are present, if an Item is edited in some way like socket system/ upgraded etc…

The 1D array stored the actual item variable and is replicated efficiently. The 2D array is well like how the 1D array is stored in a 2d plane nothing more.