如何在Unreal Engine 5中使用现代c++特性? (UE C++最佳实践)

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

如何在unreal engine 5中使用现代c++特性? (ue c++最佳实践)

Unreal Engine 5 默认使用 C++17(UE 5.3 及以后可选 C++20),但引擎自身大量封装了标准库、禁用部分语言特性,并强制使用其内存/对象生命周期管理机制。直接套用现代 C++ 惯例(如 std::shared_ptrauto 推导过度、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;
    }
}

关键限制:

  • conceptsrangesmodules 在当前 UE 构建系统中仍不被支持(会触发 Unknown type name 'concept'
  • std::format 不可用(MSVC 2019 工具链未完全实现,且 UE 自带 FString::Printf 替代)
  • 所有 UCLASS 头文件必须保持 C++17 兼容(否则反射生成器 UnrealHeaderTool 解析失败)

auto 和范围 for 在容器遍历时要注意什么?

UE 容器(TArrayTMapTSet)重载了 begin()/end(),支持范围 for,但推导类型容易出错:

PaperAiBye

PaperAiBye

支持近30多种语言降ai降重,并且支持多种语言免费测句子的ai率,支持英文aigc报告等

下载

// ❌ 危险: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。

https://www.php.cn/faq/1970313.html

发表回复

Your email address will not be published. Required fields are marked *