If-Statement not working properly in this case?

Hello.

In an inventory of weapons, when I want to equip one, I search for it inside of an array.

If found, return a pointer to the weapon itself.
If not found, return nullptr

I’m testing the case where the weapon isn’t found:



void AMyCharacter::EquipWeapon(EWeaponType toEquip)
{
	AWeapon* theWeapon = FindWeapon(toEquip);

	if (!theWeapon)
		if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, FString::Printf(TEXT("Sorry, I was not able to find the weapon")));

	else	
		if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, FString::Printf(TEXT("I found it: it's of type %d"), (uint8)theWeapon->GetWeaponType()));
}


This prints Sorry, I was not able to find the weapon as expected

Now, look at this code:



void AMyCharacter::EquipWeapon(EWeaponType toEquip)
{
	AWeapon* theWeapon = FindWeapon(toEquip);

	if ( theWeapon && theWeapon->GetIsEnabled() )
	{

	}

	else
	{
		if (!theWeapon)
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ERROR: Cannot EquipWeapon() -> theWeapon is nullptr")));				
		
		if(!theWeapon->GetIsEnabled())
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ERROR: Cannot EquipWeapon() -> theWeapon is not enabled, pick it up!")));				

		else
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ERROR: Cannot EquipWeapon() -> theWeapon is out of ammo")));		
	}
}


This code crashes giving this output:

15e5ec9686dbc33a533ee8d0dd2a0da9120fdc80.jpeg

I didn’t expect this to crash.

The if-statement here has two conditions chained with a binary operator &&.

The first is to check whether theWeapon is a valid pointer or not. In this case it’s not, so it should quickly stop going on checking the other conditions: since it’s false and the operator is an AND it has no sense to go ahead.

This is called short evaluation

Here, it seems not to work. From the crash output log I see an access violation in the GetIsEnabled() function.

What does that have to do with it?

That function shouldn’t even have been called since the first condition is false!

An actor can be != Null but still invalid.
Try it with IsValid(WeaponPointer); instead :slight_smile:

The pointer isn’t != null, it **IS **null (as seen in the first code snippet).
But still, the if-statement treats it as if it were != null

Same crash.

Are you sure it really is NULL?

Can you paste the error message of Visual Studio?

I am really, really, really sure, that short evaluation isn’t broken by UE4, because it is C++ standard, nothing UE4 could influence and your if statements aren’t anything else but booleans.
Try actively setting theWeapon = NULL; and see if it still crashes. If not, you know theWeapon wasn’t NULL;, where I am pretty certain of that this is the case.



AWeapon* theWeapon = FindWeapon(toEquip);

  
if (theWeapon && theWeapon->GetIsEnabled())
{

}


Here you check if ‘theWeapon’ is null or not. If it’s not null, you call “GetIsEnabled()” on it. This is fine so far.



else
{
	if (!theWeapon)
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ERROR: Cannot EquipWeapon() -> theWeapon is nullptr")));				
		
	if(!theWeapon->GetIsEnabled())
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ERROR: Cannot EquipWeapon() -> theWeapon is not enabled, pick it up!")));				

	else
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ERROR: Cannot EquipWeapon() -> theWeapon is out of ammo")));		
}


But here, you are in the else of the upper if clause. In this case, either ‘theWeapon’ is NULL or “GetIsEnabled()” is returning false.
If “GetIsEnabled()” is false, everything is kinda fine. It will trigger the second inner ‘if’ and print “… is not enabled…”,

BUT, if ‘theWeapon’ is NULL, the ELSE will go into the first inner ‘if’ and print “… is nullptr” and then still proceed to the second inner ‘if’ and there you call “GetIsEnabled()” on a nullptr.
That’s why you get the crash.

You would need to do this:



if (!theWeapon)
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ERROR: Cannot EquipWeapon() -> theWeapon is nullptr")));				
		
else if(!theWeapon->GetIsEnabled())
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ERROR: Cannot EquipWeapon() -> theWeapon is not enabled, pick it up!")));				

else
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ERROR: Cannot EquipWeapon() -> theWeapon is out of ammo")));	


This also makes the outer ‘if’ kinda unnecessary.

Stupid me, I didn’t examine the rest of the code… Sure, that’s the issue. I thought OP was sure that the error occurs in the first if-statement.

Thanks @exi

@eXi I completely quote @

Like him, I didn’t even take into account the rest of the code. My bad.

ttt.png