Copying FProperty from struct to struct?

I am looping through properties on a class, then I check if the property is a struct and if so loop through the struct etc. Eventually I reach an FProperty that I want to copy to another struct.

FProperty TargetProperty = StructProperty->Struct->FindPropertyByName(FName("SomeProperty"));

Normally I’d copy like this, if the copy is a simple class member to another class member (no nesting):

void* TargetAddress = TargetProperty->ContainerPtrToValuePtr<void>(InTargetWidget);
TargetProperty->CopyCompleteValue(TargetAddress, InNewValueAddress);

How to do it with a property nested in a UStruct? or even a struct in a struct?

Get a pointer to the struct instance.
For properties within struct, the “container” is the struct instance, not the object instance.
You can go as deep as you want.

FStructProperty* StructProp = (FStructProperty*)ObjectClass->FindPropertyByName("MyStruct");
void* StructInst = StructProp->ContainerPtrToValuePtr<void>(Object);
FProperty* TargetProp = StructProp->Struct->FindPropertyByName("SomeProp");
void* TargetAddress = TargetProp->ContainerPtrToValuePtr<void>(StructInst);
1 Like

Thanks for your reply. I am currently implementing the new code in an existing system. I will reply soon.

Thanks, this works well.

I have one small problem now that I’m storing struct data in a void pointer. I can get default values from a UObject already but not from a struct, possibly because the cast from void* back to (what I think should be) FStructProperty fails?

, I can’t cast it back from void to struct without getting a memory violation. Is there a workaround?:

auto FindNestedProperty = [&InPropertyPath](FProperty*& OutProperty, void*& OutContainer) {
	for (int i = 1; i < InPropertyPath.Num(); i++) {
		if (const FStructProperty* StructProperty = CastField<FStructProperty>(OutProperty)) {
			// Get the struct instance as new OutContainer.
			OutContainer = StructProperty->ContainerPtrToValuePtr<void>(OutContainer);
			
			/// .....
			/// .....
		}
	}
};


//// .....
//// .....

FStructProperty* ContainerStruct = (FStructProperty*)OutContainer;
// Memory violation at ContainerStruct->Struct.
SourceAddress = TargetProperty->ContainerPtrToValuePtrForDefaults<void>(ContainerStruct->Struct, ContainerStruct);

You are mixing up types.
Container is not a FStructProperty. FStructProperty is found via UClass/UStruct → FindPropertyByName (or TPropertyIterator).
FStructProperty doesn’t contain any value, it contains information about the property within its containing class/struct.
With FStructProperty->ContainerPtrToValuePtr you get a pointer to the struct values in memory.

  • FStructProperty = the reflection info
  • void* container = the instance values

These two objects are in completely different places in memory.

If your nested property is of type FVector, then you could cast OutContainer to FVector*.

You probably want to add the iterating StructProperty (or StructProperty->Struct) as an out parameter in your lambda, so you get both the struct instance and its reflection data.

Alternatively you can probably access the UScriptStruct back from FProperty via Cast<UScriptStruct>(OutProperty->GetOuter()) but I’m not 100% sure about that.

1 Like

It all works now