What is RF_Transactional? in SetFlags

Hey all.

I’m getting a crash when an object gets garbage collected. The object is set to RF_Transactional in its flags. But I can’t find any salient documentation for what that flag actually means.

For the record, this is in EnvQueryTypes.h there’s a FEnvQueryOptionInstance with a pointer to the generator that appears to be getting GC’d and I’m trying to see where that might be happening. I guess I could call the SetFlags and tell it not to GC, but I’m suspecting this is a result of another error, so want to track down the root cause of it not having a reference keeping it around anyway.

So anyone know what transactional flag actually does? I understand thats a long shot :slight_smile:

Ta.

I haven’t really checked this, but my assumption has been that it just marks an object as being included within transactions for the purposes of the undo/redo system within the editor. Editor code will often wrap modifications within an FScopedTransaction, and I’m assuming this is what the flag relates to.

Pretty sure it shouldn’t have any direct bearing on garbage collection.

Hmm, i wonder why its not using a TSharedPtr then in the definition? Its using a raw pointer and presumably its meant to be used by something that keeps it around. The generator itself is created with NewObject so I assume that throws it into the GC? I was wondering if that flag somehow was meant to stop it being collected. But i guess it was meant to be referenced some other way.

Actually debugging this code is a bit of a nightmare really. I mean so many different data structures, all with/without various levels of smart/raw/weak pointers which could potentially be released. Urgh… Then there’s all the marshalling code which makes my eyes bleed :slight_smile:

Thanks for the info anyway.

From the docs on FEnvQueryOptionInstance:

I haven’t dug into the EQS code at all, so I have no idea how it works and what the lifetime of the manager is.

My problem is that i can’t see how the manager would hold the raw pointer valid. I mean if it had a sharedptr or some such to all of those classes I could see it. But of course that struct is held by another struct and that is held by another struct and so on and so forth :wink:

I understand the architecture of it, but it just makes my eyes bleed seeing FThisTypeOfStruct and FThatOtherTypeOfThing all over the place. Oh for readable stupid code :slight_smile:

There’s no good documentation about RF Flags of UObject, so I was wondering the same thing.

I can highly recommend looking into: FProperty::ShouldSerializeValue and there we can find the code I pasted below.

// Skip properties marked NonTransactional when transacting
if ((PropertyFlags & CPF_NonTransactional) && Ar.IsTransacting())
{
	return false;
}

Be aware that this snippet relates to a property, thus it uses CPF flags, not RF flags.
If we look deeper into FArchive implementation of IsTransacting(), it is possible to find that an archive is transacting only if it contains any editor related data.

/** Returns true if this archive is transacting, which is used to keep track of changes to objects for things like the editor undo system. */
FORCEINLINE bool IsTransacting() const
{
	if (FPlatformProperties::HasEditorOnlyData())
	{
		return ArIsTransacting;
	}
	else
	{
		return false;
	}
}

All this confirms that “transactional” term is indeed related to undo/redo system of the editor. The only question remains what exactly RF_Transactional means, when marking an entire object. I can only assume that objects not marked with such a flag are discarded early when preparing data for the undo/redo system.