Discussion: The (ab)use of IsValidLowLevel

Hey guys,

There’s a few habits floating around the community that I’m not too keen on. One of them is calling IsValidLowLevel to verify the validity of objects.

While it does include a null check, which is reasonable practice, it also does a bunch of extra checks which, frankly, are not necessary. Do a search across the codebase to see for yourself – apart from select few exceptions (mostly in editor/non-shipping code), Epic doesn’t use IsValidLowLevel outside of debug checks. Simply put, this is because the extra checks will never fail if you use UObjects properly. The only way these can fail is if you are somehow trying to access a UObject pointer that was garbage collected from under you.

Given the two mechanisms we have for dealing with UObjects (managed UPROPERTY() pointers and TWeakObjectPtr), this situation should never happen. When you don’t want an object to be collected for as long as you need it, you make it a property. If you just want to have a weak dependency to an object you don’t own but do want to keep track of, you use TWeakObjectPtr and make sure to call IsValid.

We don’t use IsValidLowLevel anywhere in our codebase and it has never been necessary. The extra checks aren’t too expensive, but if people start using IsValidLowLevel instead of simple null pointer checks, they certainly will add up. But the ugly part is that since the extra checks merely fail with a log warning, using IsValidLowLevel could actually hide what would otherwise be serious, crash-causing issues.

Any thoughts?

I have no doubt you’re right. I had seen use of this in a couple of wiki tutorials and without looking into it, had assumed it wasn’t really intended to be used, just from the name essentially.

I think to be honest though, it’s just one symptom of the general lack of C++ documentation and best practices guidance. If people are using this, no doubt it’s largely due to the influence of Rama’s Wiki tutorials. Don’t get me wrong, from the perspective of someone new to UE4, it looks to me like he’s probably done more for the community than anyone else. But I suspect when he wrote many of his tutorials he was battling with the engine source code with even less documentation and help than we have now, so it’s to be expected that some of what he found to work may not be intended usage, or may only have been necessary back then due to engine bugs.

Bottom line is, until there is far more in depth explanation and documentation of UE4 C++ from Epic, people are going to continue to go it on their own and inevitably pick up heaps of bad habits and wrong ideas. Then, through attempting to be helpful, they’ll pass them on to others. Hence my suggestion here that it would be better for all if there was a change of tack by Epic to focus for a while more on educating the community to understand what we have, instead of continuing to add more engine features.

Apologies for the slightly off topic rant and kudos for taking the time to point this out.

Why I Use IsValidLowLevel

Hi there!

First of all I want to say to CMartel that I appreciate your presence in the forums, and I have been very happy to see you helping so many people!

I did not use IsValidLowLevel() due to lack of documentation, IsValidLowLevel() was the only thing that made my Beta in-game Editor stable as I was frequently destroying and creating UObjects at runtime from user-input.

Below is a video of my in-game editor where I make a Blood Cell Galaxy in about 8 min using my in-game c++ tools!


**Red Blood Cell Galaxy Video**

The video demonstrates my in-game editor's undo-redo feature which has infinite storage capacity!

I also demonstrate my multi-selection system, and copy-pasting and translating/rotating/scaling of whole groups of actors.

All of this is done with the UE4 editor closed, and my levels are saved to hard disk and can be loaded any time using custom serialization code :) 

In this UE4 Beta project I essentially made my own c++ level editor that I could ship with my game and people could share their own levels using my custom file format.

https://youtube.com/watch?v=1vCToatFbHI

IsValidLowLevel()

While making my in-game editor, I encountered cases where a UObject pointer was still valid, but its internal data was partially deconstructed already, as I was dynamically spawning and deleting actors quite frequently (its an in-game editor after all).

In this circumstance, doing a simple pointer check was insufficient, and my game was crashing because the interior UObject data was already partially destroyed but the pointer was still valid.

I found that IsValidLowLevel() was the only way to verify the full integrity of the UObject.

I agree that in many cases this extra check is not necessary!

You should use your own judgement as to whether you feel IsValidLowLevel() will help you or not.

The main thing you can take away from this post of mine is that if you ever get inexplicable crashes with UObjects using only simple pointer validity checks, you should certainly try out IsValidLowLevel()

Ever since my experience during the Beta, I chose to always be as safe as possible and do IsValidLowLevel() checks.

I’ve had cases where doing this extra check has helped in multiplayer games with replicated proxies being passed via Server function, and people besides myself have also encountered this.

However I agree it is not the majority case or even a common experience, so you should feel free to use your own judgement about whether IsValidLowLevel() is a required check.


**4.7**

Furthermore, the UObject improvements in 4.7 might have removed the cases I was encountering from the Beta, I am not sure yet whether this is so due to lack of time testing 4.7.

**Summary:**

Use your own judgement! 

I showed the safest possible case in my wiki tutorials, but please use your own judgement as to whether IsValidLowLevel() will benefit your game as an extra stability check.

It is a minority case that can still crash your game, so that's why I include the extra safety check in my wiki tutorials.

Enjoy!

Rama

@kamrann: It might just be old ingrained habits, but to me, the C++ code is the documentation. UE4 being a fairly feature rich engine, it can be a bit tricky to follow certain functionality, but so far the only things I haven’t been able to figure out through observation and experimentation is the intricate backend workings of Blueprints. They get compiled to bytecode and then it’s all a fun magical black box to me.

@Rama: I’d be genuinely curious to see under what kind of circumstances you’ve had invalid objects. We do an aggressive amount of dynamic actor spawning/despawning as part of our procedural world generation and haven’t really encountered that kind of issue. I actually thought to broach the subject because for the first time, I managed to create a set of references that resulted in a UObject being garbage collected too early… But even then, it’s only during teardown of the game, from a fairly unorthodox mixed Slate-UMG hierarchy. In that one case, IsValidLowLevel would detect this happening, but I’m more inclined to fix the way my widgets are being referenced than modify SObjectWidget to add that check.

In any event, thanks to you as well for your many tutorials. I’ve been kicking around with UE4 since a little bit after it was available to custom licensees, so I have a lot of accumulated research I’d like to share, but just don’t have the time or patience to make documentation for it. It’s great that someone is doing it, in the meantime I’m happy to just chime in on the more arcane UE4-specific questions. :slight_smile:

But one of these days I’ll undertake the massive task of documenting the different initialization paths of Objects, Actors and subobjects, both native and blueprinted, in editor builds and shipping builds… I still don’t feel confident enough to paint that picture.

I understand where you’re coming from, and it’s commendable that you have got to where you are without feeling the need for more documentation. Personally, though I’ve spent a fair bit of time already following through engine code, I have often had to give up and come up with a workaround, or move onto something else for a while. I find that there are just so many interdependent components. Often I step through with the debugger, feeling sure I’m about to reach the point in code of the functionality I’m looking for, only to find that all it does is set some variable and back out, leaving me with the task of looking for all other places that make use of said variable and trying to figure out the relative order in which they are all called and how it fits together.

I guess at the end of the day though, it’s essentially a question of aims and time investment. The whole idea for most people with a licensed game engine is to use it’s functionality and so avoid having to reinvent the wheel. They have no intention of understanding its intricate workings, they just want a level of understanding sufficient to be able to use it properly, thereby allowing their time to be spent on higher level logic. Currently, I feel like attaining even that base level of understanding is difficult and very time consuming, which is not ideal.

As somewhat of a UE C++ newbie here myself, I stumbled on this post trying to figure out IF it was bad practice to be using IsValidLowLevel() too frequently. Fortunately, I got my answer here-- thanks guys!. Unfortunately, I’m not quite sure what I SHOULD be using as an acceptable replacement for the IsValid blueprint node. I have currently been using IsValidLowLevelFast() for most of my checks, but I’m not sure if there is a better method to call for this. Since other people may stumble on this post, maybe one of you veterans could respond to the following:
What is the best general purpose replacement for the IsValid BP node in C++?

I suspect the pervasiveness of this in the community is the result of people like me–those transitioning from blueprints to c+±-not having the access to more useful C++ documentation, and making assumptions based upon the names of methods and Blueprint nodes. Best practice guides are fantastic. The truth is though: reading is crucial, but it’s VERY helpful to not have to dig through piles of source code and hierarchy to figure out how stuff is working. Much faster to read the explanations of the people who wrote it.

EDIT: Saw this above:

Totally Agree. My interest is in understanding the engine enough to provide my customers and clients with what they want as quickly as possible. This means spending as few hours as possible dissecting source code to figure out how everything works.

IsValidLLFast() is somewhat new function.
You can use it to check UObjects, no problem.
This topic is just paranoid thinking although the first version of IsValidLowLevel() is really a bit slow.

If you want you can just (object == nullptr) as well or use TSharedPtr<>.

If you need extreme safety you can also use the check(…) macros, they rise exception if object is invalid; it’s awesome for deep low functions you assume the target object should never ever be null.

This page has some disinformation.
If you are using UObject pointers correctly (usually by marking them as UPROPERTY), you should NEVER use UObject::IsValidLowLevel(), as that’s only meant for internal usage (for GC internal checks), and it could crash if you have a dangling pointer (which the very same thing you’d call this function for). Just use IsValid(UObject), that is all you ever need.
See this page for more info: Memory Management | Unreal Engine Community Wiki