In general, yes, it is usually best practice to guard against dereferencing nullptrs (google ‘defensive programming’ to read up on other common best practices).
I say ‘usually’ here because sometimes during the development cycle we actually want the program to crash if the code tries to access an invalid pointer. The reason for this is that in certain situations we assume that the pointer being dereferenced should always point to a valid object. The problem with checking for nullptr in these situations is that we might end up with undefined behavior at runtime if execution is allowed to continue, which would be the case if we protected against accessing an invalid pointer.
Keep in mind that the intent to crash on an invalid pointer may not always be clear to other team members (or even to yourself as time passes). This is where the ensure
and check
macros come in handy because they more clearly express the original programmer’s intent. For example:
// Use the ensure macro to show a warning that SomeObjectPtr should
// be valid at this point, but we're allowing execution to continue anyway.
// ensure() will also break into the debugger on first failure if one is attached.
if (!ensure(SomeObjectPtr != nullptr)) { /* warn and continue */ }
// Use the check macro to halt program execution completely.
// check() will also break into the debugger if one is attached.
check(SomeObjectPtr != nullptr); // fatal error if SomeObjectPtr is null.
// or
// Check if SomeObjectPtr is not null and points to a live object that is not pending kill
check(IsValid(SomeObjectPtr));
Lots more info on UE’s built-in assertion macros here.
Lastly, we don’t want the program to crash on the user’s machine, so in general it’s good thoroughly exercise code that assumes pointer validity.