UE5默认C++17,禁用std::unique_ptr管理UObject因GC冲突;C++20仅限非UCLASS模块;范围for需用const引用避免拷贝;蓝图函数参数须用TArray/TMap而非span/View。

Unreal Engine 5 默认使用 C++17(UE 5.3 及以后可选 C++20),但引擎自身大量封装了标准库、禁用部分语言特性,并强制使用其内存/对象生命周期管理机制。直接套用现代 C++ 惯例(如 std::shared_ptr、auto 推导过度、RAII 构造函数抛异常)极易引发崩溃或资源泄漏。
为什么不能直接用 std::unique_ptr 管理 UObject 子类?
UE 的垃圾回收(GC)系统依赖 UObject 的反射信息和根引用链,而 std::unique_ptr 是纯栈/堆语义,不参与 GC 注册。一旦你用它持有 UCLASS 实例,GC 会认为该对象不可达并销毁它,而 std::unique_ptr 还在试图管理已释放内存 —— 下次访问必崩。
正确做法是用 UE 原生指针类型:
-
TObjectPtr(推荐,UE 5.2+ 引入,类型安全、支持 GC、可序列化) -
UActorComponent*(需手动确保生命周期,例如在BeginDestroy()中置空) - 避免
UActorComponent**或裸void*转换
如何安全启用 C++20 并避开 UE 编译器陷阱?
UE 5.3+ 支持 C++20,但仅限非 UCLASS / USTRUCT 的普通模块(如 Runtime/Core 或自建工具模块)。在 Build.cs 中设置需谨慎:
立即学习“C++免费学习笔记(深入)”;
public override void SetupBinaries(
target,
ref List OutBinaries
)
{
base.SetupBinaries(target, ref OutBinaries);
// 仅对非UObject模块启用C++20
if (Target.Type != TargetType.Editor && !IsInUObjectModule())
{
CppSettings.LanguageStandard = CppLanguageStandard.Cpp20;
}
}
关键限制:
-
concepts、ranges、modules在当前 UE 构建系统中仍不被支持(会触发Unknown type name 'concept') -
std::format不可用(MSVC 2019 工具链未完全实现,且 UE 自带FString::Printf替代) - 所有
UCLASS头文件必须保持 C++17 兼容(否则反射生成器UnrealHeaderTool解析失败)
auto 和范围 for 在容器遍历时要注意什么?
UE 容器(TArray、TMap、TSet)重载了 begin()/end(),支持范围 for,但推导类型容易出错:
// ❌ 危险:TArray的 value_type 是 FString,但 operator[] 返回的是 FString& TArray Names = {TEXT("A"), TEXT("B")}; for (auto Name : Names) // 复制每项!大字符串开销高 { DoSomething(Name); } // ✅ 推荐:显式 const 引用避免拷贝 for (const FString& Name : Names) { DoSomething(Name); } // ✅ 或用索引(当需要下标时) for (int32 i = 0; i < Names.Num(); ++i) { DoSomething(Names[i]); }
额外注意:
-
TMap的范围for迭代的是TPair,不是ValueType - 不要在循环中调用
Add()或RemoveAt()—— UE 容器不保证迭代器失效行为与 STL 一致,可能跳项或崩溃
如何在蓝图暴露的函数中用现代 C++ 参数风格?
UE 的 UFUNCTION 反射不识别模板、概念或复杂别名。以下写法均无效:
-
UFUNCTION(BlueprintCallable) void SetData(TArrayView(Data); TArrayView不被蓝图识别) -
UFUNCTION(BlueprintCallable) void Process(std::span(Values); std::span无反射信息) -
UFUNCTION(BlueprintCallable) void Configure(const TMap(引用参数蓝图无法传入)& Config);
可行方案:
- 输入统一用
const TArray、& const TMap—— UE 会自动转换蓝图数组/字典& - 输出用
UPARAM(Ref)标记的非 const 引用(如UPARAM(Ref) TArray)& OutPoints - 若需高性能只读视图,内部转成
TArrayView,但签名仍用TArray
例如:
UFUNCTION(BlueprintCallable, Category = "Math") void NormalizeVectors(const TArray& InVectors, TArray & OutNormalized); // 内部可写:TArrayView View(InVectors);
最常被忽略的一点:UE 的 USTRUCT 成员变量即使声明为 const,也无法阻止蓝图或序列化修改它 —— 反射系统绕过 const 限定。真正想保护数据,得靠逻辑层校验或私有变量 + 公共 getter。











