UE4 C++ TMap中存储的FActorSpawnParameters.Template调用GetOwner返回空
问题原因分析
- 核心原因为UObject引用未被UE垃圾回收(GC)系统识别,导致对象被意外回收:
你将FActorSpawnParameters存储在非UObject类型的FInventoryTupleKey结构体中,且该结构体通过普通C++智能指针TSharedPtr包装,结构体内部的Template、Owner等UObject指针成员没有被标记为UPROPERTY,UE的GC扫描时无法识别到这些指针还在引用对应的UObject。一旦对应的Actor没有其他被GC识别的引用持有,就会被GC回收,导致访问时指针失效,GetOwner()自然返回空值。 - 验证方法:你可以在存入参数和遍历读取的位置分别打印
SpawnParams.Template的指针地址,确认两次访问的指针是否一致,如果后续指针变为0x0,即可确定是GC回收导致的问题。
修复方案
- 首选方案:调整存储结构,让UObject引用被GC正确识别
将FInventoryTupleKey改为继承自UObject的类型,内部涉及UObject的成员标记为UPROPERTY(),这样GC扫描时会保留对应的对象引用,不会被意外回收,同时废弃TSharedPtr,直接使用UE的对象指针管理生命周期。
示例修改参考:
UCLASS() class UInventoryTupleKey : public UObject { GENERATED_BODY() public: UPROPERTY() FActorSpawnParameters ActorSpawnParams; int32 Count; // 你的其他自定义成员 };
对应的TMap定义修改为:
UPROPERTY() TMap< TSubclassOf<class ACollectable>, UInventoryTupleKey* > InventoryElements;
- 临时方案:手动添加根引用避免GC回收
如果不想修改原有结构体定义,可以在存入TMap时给需要保留的UObject手动添加根引用:
SpawnParams.Template->AddToRoot();
在对应元素从TMap中移除、不再需要时调用SpawnParams.Template->RemoveFromRoot()释放引用即可。该方案需要手动管理生命周期,处理不当容易出现内存泄漏,仅推荐临时调试使用。
3. 额外优化建议:FActorSpawnParameters本身是用于生成Actor的临时参数结构,并不适合长期存储,你可以直接拆分存储模板Actor、Owner、生成碰撞规则等你实际需要的字段,不需要完整存储整个FActorSpawnParameters结构,避免引入不必要的问题。
内容的提问来源于stack exchange,提问作者محمد خير الخلق
相关产品推荐
相关产品推荐

