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