Unreal Engine中动态创建TArray并让垃圾回收追踪的技术问询
问题
我有一个继承自UObject的类,其中包含一个标记为UPROPERTY的TArray:
UCLASS(BlueprintType, Blueprintable) class SOME_API UClassA : public UObject { GENERATED_BODY() public: UPROPERTY(EditAnywhere, BlueprintReadWrite) TArray<UObject*> Objects; };
尝试用NewObject动态创建TArray并赋值给Objects时触发编译错误:
UClassA* ObjA = NewObject<UClassA>(); TArray<UObject*>* NewArray = NewObject<TArray<UObject*>>(); // 编译错误处 ObjA->Objects = *NewArray;
错误信息:
Error C2039 : 'StaticClass': is not a member of 'TArray<UObject *,FDefaultAllocator>' Reference C2039 : see declaration of 'TArray<UObject *,FDefaultAllocator>' Reference C2039 : see reference to function template instantiation 'T *NewObject<TArray<UObject *,FDefaultAllocator>>(UObject *)' being compiled with [ T=TArray<UObject *,FDefaultAllocator> ]
我的疑问:
- 能否用C++的
new来创建TArray?这样做是否可行? - 垃圾回收器会追踪这个新创建的数组,而非构造函数中创建的
Objects数组吗?
补充:我打算动态创建TArray及其包含的UObject对象,且希望UE垃圾回收器能识别它们,这将是它们唯一的存储位置。
解答
为什么NewObject创建TArray会报错?
NewObject是Unreal Engine专门用来创建UObject派生类实例的函数,它依赖类的StaticClass()方法获取UClass信息。而TArray是UE的容器值类型,并非UObject的子类,没有StaticClass()方法,因此无法用NewObject创建。
能否用C++的new创建TArray?
可以,但完全没必要,还会引入额外问题:
TArray是轻量级值类型,设计为直接在栈上或作为对象成员使用,用new会把它分配在堆上,需要手动调用delete释放,否则会造成内存泄漏。- 即使你用
new创建了TArray,赋值给ObjA->Objects时会执行值拷贝,原堆上的TArray如果没有其他指针引用,就会变成无人管理的内存垃圾。 - UE的GC不会追踪堆上的TArray本身(因为它不是UObject),但数组中存储的UObject如果被
ObjA->Objects(UPROPERTY标记)持有,只要ObjA处于GC追踪链中,这些UObject会被正常管理。
正确实现需求的方式
无需额外创建TArray实例,直接操作ObjA->Objects即可——它本身就是一个初始化完成的TArray,你只需要往里面添加动态创建的UObject:
UClassA* ObjA = NewObject<UClassA>(); // 动态创建UObject并加入数组,将ObjA作为Outer确保GC追踪 UObject* NewObj1 = NewObject<UObject>(ObjA); ObjA->Objects.Add(NewObj1); UObject* NewObj2 = NewObject<UObject>(ObjA); ObjA->Objects.Add(NewObj2);
如果需要替换整个数组,直接用栈上的临时TArray赋值即可:
UClassA* ObjA = NewObject<UClassA>(); TArray<UObject*> TempArray; TempArray.Add(NewObject<UObject>(ObjA)); TempArray.Add(NewObject<UObject>(ObjA)); // 直接赋值,原Objects数组的内容会被自动清理 ObjA->Objects = TempArray;
关键注意点
- 动态创建UObject时,必须指定一个有效的
Outer(比如上面的ObjA),或者将其加入到UPROPERTY标记的容器中,这样UE的GC才能识别并管理这些对象。 ObjA本身需要被GC追踪(比如作为其他UObject的成员、被蓝图引用,或者加入到GetWorld()->GetGameInstance()等全局对象的引用链中),否则ObjA和它的Objects数组中的对象都会被GC回收。
内容的提问来源于stack exchange,提问作者Unicorn
相关产品推荐
相关产品推荐

