Im having a bug that only happens when if i dont use UELOG:

My function only works IF i use a UELOG in the middle of it.
So its super weird.
I found this out because i was trying to debug it, and when i debug it using UELOG, everything works fine.

Why would using a UELOG make things suddenly work, and not using make things not work?

I tried all kinds of things to understand what is happening. Im using visual studio and UE4.
Additionally this is quite a problem because how can i debug things, if they work when debugging, but dont work when not debugging?

Should i try to rebuild / generate visual studio project files?
What should i do?

Here is someone with a similar problem:

Full code, sorry for the length:

void UMeleeComponent::MoveInstancesByCheckpoints(float delta) {
	FVector V;
	FTransform T;
	float speed = 60.f; //must get it from the data table structure of the main actor.
	int32 inst;
	FVector CurCheckpoint;
	for (int32 i = MovingUnits.Num() - 1; i >= 0; i--)
	{
		inst = MovingUnits[i];
		V.X = MainBatOwner->GetInstanceCustomDataValue(OwnerISM, inst, 5);
		V.Y = MainBatOwner->GetInstanceCustomDataValue(OwnerISM, inst, 6);
		CurCheckpoint = CurCheckpoints[i];

		//GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::Magenta," Next Checkpoint: " + FString::FromInt(inst));
		UE_LOG(LogTemp, Log, TEXT(" instance loc: %s"), *CurCheckpoint.ToString());
//using one of these 2 logs will fix the function misteriously.

		V = FMath::VInterpConstantTo(V, CurCheckpoint, g_DeltaTime, speed);
		OwnerISM->SetCustomDataValue(inst, 5, V.X, false);
		OwnerISM->SetCustomDataValue(inst, 6, V.Y, false);
		if (V.Equals(CurCheckpoint, 0.001)) {
			if (MovingUnits.Num() != FutureCheckpoints.Num()) {
				UE_LOG(LogTemp, Warning, TEXT("ActiveCheckpointsIndex size: %d"), ActiveCheckpointsIndex.Num());
			}
				int32 c_index = ActiveCheckpointsIndex[inst];
				ActiveCheckpointsIndex[inst]++;
				if (!FutureCheckpoints.Contains(inst))
					goto RemoveFromMovingUnits;
				if (c_index < FutureCheckpoints[inst].CheckpointLocations.Num()) {

					CurCheckpoints[i] = FutureCheckpoints[inst].CheckpointLocations[c_index];
CurCheckpoints[i], CurCheckpoint); //this also works but was bugging dont know why.

					FTransform T_Rotate;
					OwnerISM->GetInstanceTransform(inst, T_Rotate, true);
					FRotator newrot = (CurCheckpoints[i] - CurCheckpoint).Rotation();
					T_Rotate.SetRotation(FQuat(newrot));
					OwnerISM->UpdateInstanceTransform(inst, T_Rotate, true, false, false);
				}
				else {
					RemoveFromMovingUnits:
					MovingUnits.RemoveSingleSwap(inst);
					CurCheckpoints.RemoveSingleSwap(V);
					ActiveCheckpointsIndex.Remove(inst);
					FutureCheckpoints.Remove(inst);
					MainBatOwner->Restore_WPO_Position_S_Safe(OwnerISM, inst);
					switch (MainBatOwner->UnitState[inst]) {
					case Attack:
						FindEnemyToEngage(inst);
						break;
					}
				}
			//}
		}
	}
	OwnerISM->MarkRenderStateDirty();
}

Found out that this also fixes the bug, and units move as expected:

	for (int32 i = MovingUnits.Num() - 1; i >= 0; i--)
	{
		inst = MovingUnits[i];
		V.X = MainBatOwner->GetInstanceCustomDataValue(OwnerISM, inst, 5);
		V.Y = MainBatOwner->GetInstanceCustomDataValue(OwnerISM, inst, 6);
		CurCheckpoint = CurCheckpoints[i];
		FVector HackyCheckpointCopy = CurCheckpoints[i]; //this works too.
		V = FMath::VInterpConstantTo(V, HackyCheckpointCopy, g_DeltaTime, speed);

So basically creating a variable inside the loop rather than reusing the same variable for all iterations, which i thought is good for performance.

Though this is what i wanted:

FVector CurCheckpoint;
	for (int32 i = MovingUnits.Num() - 1; i >= 0; i--)
	{
		inst = MovingUnits[i];
		V.X = MainBatOwner->GetInstanceCustomDataValue(OwnerISM, inst, 5);
		V.Y = MainBatOwner->GetInstanceCustomDataValue(OwnerISM, inst, 6);
		CurCheckpoint = CurCheckpoints[i];
		V = FMath::VInterpConstantTo(V, CurCheckpoint , g_DeltaTime, speed);

But there must be some weird compiler optimization going on, that makes the CurCheckpoint not work. Which is weird, because it works the moment you include a UELOG or AddDebugMessage.

Hi,
Without looking too deeply into your code, my guess is that you have a memory corruption. e.g. writing into index 4 of an array with a length of 4 (last valid index=3).
What all you ‘solutions’ have in common is that they change the stack frame and you could therefore be overwriting different memory resulting in different behavior.
I hope this helps.

1 Like

It turns out the problem was because im making a vector using only two dimensions X and Y. I assumed that the Z would be default 0. It turns out its some high number like 91919129932139.

These bugs are are to find out because the code seems to work in debug mode. But i got it now. Thanks.

You figured out the answer, but here’s some elaboration on the issue.

In C++, if classes/structs don’t zero-initialize their members then they will basically be whatever value happened to previously reside at that memory address.
(This depends also on how the compiler optimizes the code, which might sometimes make it start all zero, but that will just be by luck.)

Often classes/structs will explicitly initialize their member variables to some default value, like zero, in their constructor. But if you look at FVector’s constructor you’ll see this:
Engine\Source\Runtime\Core\Public\Math\Vector.h

/** Default constructor (no initialization). */
FORCEINLINE TVector();

// A bit lower in that same file...

template<typename T>
FORCEINLINE TVector<T>::TVector()
{}

As you can see in FVector’s constructor (FVector is just forward declared TVector<double>) it doesn’t initialize its own member variables (x, y, z) on purpose. This is done for optimization purposes, you only want to spend the CPU cycles zero initializing a vector when you need to.

Here are a bunch of different ways of creating FVectors:

FVector MyVector; // Not initialized, will have garbage values
FVector MyVector{}; // Not initialized, will have garbage values
FVector MyVector = {}; // Not initialized, will have garbage values
FVector MyVector = FVector(); // Not initialized, will have garbage values
FVector MyVector(0); // Zero initialized (0, 0, 0)
FVector MyVector(0, 0, 0); // Zero initialized (0, 0, 0)
FVector MyVector{0}; // Zero initialized (0, 0, 0)
FVector MyVector(EForceInit::ForceInitToZero); // Zero initialized (0, 0, 0)
FVector MyVector = FVector(0); // Zero initialized (0, 0, 0)
FVector ZeroInitialized = FVector::ZeroVector; // Zero initialized (0, 0, 0)

If you want to zero initialize an FVector then usually you’d want to use FVector ZeroInitialized = FVector::ZeroVector; as Epic does in its own code base.

It is also perfectly fine to create an non-zero-initialized FVector in a function if you just set its values in the same or next line, or at least before you use it.

1 Like

Thanks so much to explain us this in detail. Now it makes perfect sense the random high number that was appearing in the Z and therefore messing up my code.

1 Like