[C++] Array of Instanced UObjects NULL after BP Compile

I’m seeing all my instanced objects not being properly copied over to the new CDO once the BP compiles. The array still has the same number of entries, but each entry is now a nullptr. I’m using a custom editor that inherits from BlueprintEditor to modify the entry so I’m curious if this is on my end, or just a bug.

Also this may be the same issue as described here:

To repro it, add an array of instanced UObject*'s like so to a Blueprint class:

UPROPERTY(EditDefaultsOnly, Instanced, Category = "Internal")
TArray<UObject*> InstancedObjects;
  1. Modify the array someway (directly through the property editor is probably the easiest).
  2. Save your class/data-only BP.
  3. Re-open the editor and verify your properties are still there.
  4. Now modify the BP some way (e.g. Add a simple Print node) and hit compile.
  5. Notice your array is now filled with nullptrs (but the number of elements is correct).

I’ve worked around this temporarily by caching off the values pre-compile and then restoring them post-compile, but man does it feel gross/hacky.

Let me know if you need me to provide you code/examples.

Cheers!

Update:
Looks like my Pre/Post Compile hack isn’t always working (specifically during automatic recompile when the editor first opens - still trying to find out why).

I figured things out.

So, the field was marked instanced, but the class it was instantiating wasn’t marked as EditInlineNew in a few child classes that derived from a common abstract uobject. So it would see the reference, go to copy it, but fail this logic check in the Duplicate method in InstancedReferenceSubobjectHelper.h:

					const bool bProperOuter = (Obj->GetOuter() == OldObject);
					const bool bEditInlineNew = Obj->GetClass()->HasAnyClassFlags(CLASS_EditInlineNew | CLASS_DefaultToInstanced);
					if (bProperOuter && bEditInlineNew) <- bEditInlineNew was false in this case.
					{
						const bool bKeptByOld = OldEditInlineObjects.Contains(Obj);
						const bool bNotHandledYet = !ReferenceReplacementMap.Contains(Obj);
						if (bKeptByOld && bNotHandledYet)
						{
                                // Actual Duplicate work...
						}
					}

So, my fault. It might be nice to have a warning if the for some reason this Duplicate fails (rather than silently failing) given it’s copying known instanced objects from one object to another so a failure here is pretty nasty and you just end up with null pointers in containers, etc in the destination object.