news 2026/6/9 18:11:49

《Unreal 对 C++ 做了什么》系列 04. USTRUCT 与 UPROPERTY:数据结构的反射化与变量管理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
《Unreal 对 C++ 做了什么》系列 04. USTRUCT 与 UPROPERTY:数据结构的反射化与变量管理

《Unreal 对 C++ 做了什么》系列 (04/54)

04. USTRUCT 与 UPROPERTY:数据结构的反射化与变量管理 💎(深挖版)

🚀 导言:为什么裸 C++ 变量在 UE 里是“瞎子”?

在标准 C++ 中,如果你定义了int32 Health;,编译器只会在内存里留出 4 个字节。程序运行起来后,除了你的代码,没有人知道这 4 个字节代表“血量”。

虚幻引擎通过USTRUCTUPROPERTY为这段内存贴上了**“身份标签”**。


🔑 USTRUCT:伪装成类的数据包

虽然USTRUCT在 C++ 层面上是个结构体,但在 UHT 看来,它是一个**“被剥夺了部分权力的 UClass”**。

1. 它没有“户口” (No Path)

UObject都有一个在引擎内部的路径(如/Game/Maps/Level1.ActorA),但USTRUCT没有。它必须寄生在某个UObject的内存块里,或者作为一个局部变量存在。

2. 内存对齐与反射

当你在USTRUCT里写下GENERATED_BODY()时,UHT 会生成一个StaticStruct()函数。

  • 标准 C++ 痛点:你无法通过变量名字符串(如 “Health”)去访问结构体成员。
  • UE 解决方案UScriptStruct。每一个USTRUCT都有一个对应的UScriptStruct元数据对象。它记录了结构体的大小、对齐方式以及每个成员的偏移量。

⚡ UPROPERTY:内存的“监控探针”

这是虚幻 C++ 的灵魂宏。我们将它拆解为三个层面:

1. 自动清空机制(生命周期的保护神)

这是新手最容易忽视的一点。

  • 裸指针AActor* MyActor;。如果MyActor在关卡里被销毁了,你的指针依然指向原来的地址(野指针),访问即崩溃。
  • UPROPERTY 指针UPROPERTY() AActor* MyActor;。当该 Actor 被销毁时,UE 会遍历所有引用它的UPROPERTY指针,并**强行将其设为nullptr**。这就是为什么 UE 推荐你访问指针前先做if(MyActor)判断。
2. 说明符(Specifiers)的深层逻辑

说明符不是注释,它们直接改变了 UHT 生成的代码逻辑:

  • **EditAnywherevsEditInstanceOnly**

  • EditAnywhere:在蓝图类(原型)和场景实例中都能改。

  • EditInstanceOnly:只能在摆放到场景里的那个“分身”上改。这在内存上涉及到CDO (Class Default Object)的数据覆盖机制。

  • BlueprintReadOnly:UHT 会在生成的代码中,拒绝为该变量生成“写入”权限的反射接口,即使你在 C++ 里它是public的。

3. 内存布局的“黑盒”访问

UE 的编辑器面板(Details Panel)其实是一个“内存编辑器”。
当你拖动滑动条修改血量时,流程如下:

  1. 编辑器通过反射找到该变量的FProperty对象。
  2. FProperty存储了相对于类起始位置的Offset(偏移量)。
  3. 编辑器计算:Address = (Byte*)ObjectInstance + Offset
  4. 直接往这个内存地址里写值。
    这就是为什么即使你的变量是private的,只要加了UPROPERTY(EditAnywhere),编辑器依然能改它——因为它绕过了 C++ 访问权限,直接操作内存。

🛠️ 进阶:TArray/TMap 与 UPROPERTY 的化学反应

如果你的容器里装的是UObject*必须UPROPERTY

// 错误:GC 扫描不到容器内部,里面的 Actor 随时会被回收,留下满地野指针TArray<AActor*>MyActors;// 正确:UE 的 GC 系统会递归扫描容器内部的每一个元素,保护它们的生命周期UPROPERTY()TArray<AActor*>MyActors;

⚠️ 总结:UE 对你的变量做了什么?

特性标准 C++虚幻 C++ (UPROPERTY)
存在感编译后消失运行时全局可查 (Reflection)
安全性需手动置空,否则野指针自动置空 (Auto-nulling)
可达性只能通过代码访问编辑器、蓝图、序列化系统均可访问
内存成本只有变量本身大小变量大小 + 反射系统中的元数据开销

结语

在 UE 中,UPROPERTY是你和引擎之间的契约。你通过宏告诉引擎:“请帮我看着这个变量”。作为回报,引擎赋予了它在编辑器里变现、在网络里同步、以及在 GC 中幸存的能力。


下一篇我们将深入探讨:《05. UFUNCTION:让函数在引擎内可见 (RPC, Exec, Blueprint)》,我们将看看 UE 如何让一个 C++ 函数跨越语言界限,被蓝图甚至网络另一端的电脑调用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 3:38:45

EmotiVoice本地部署教程:在私有服务器上运行情感TTS

EmotiVoice本地部署教程&#xff1a;在私有服务器上运行情感TTS 在虚拟主播深夜直播、智能客服温柔致歉、有声书自动演绎悲欢离合的今天&#xff0c;语音合成早已不再是“机器念稿”的代名词。用户期待的是能传递情绪、带有温度的声音——而这种需求&#xff0c;正在推动TTS技术…

作者头像 李华
网站建设 2026/6/10 1:15:02

2026年游戏开发黄金赛道深度解析

在即将到来的2026年&#xff0c;游戏开发领域的增长动力正发生结构性转移。市场分析报告指出&#xff0c;元宇宙应用、沉浸式VR体感互动与功能化教育游戏三大板块已确立其增长优势&#xff0c;预计年复合增长率分别为29.3%、25%和20%&#xff0c;正共同构成驱动未来市场发展的核…

作者头像 李华
网站建设 2026/6/10 12:14:50

3个常见错误+4步解决方案:彻底搞定Monaco Editor集成难题

3个常见错误4步解决方案&#xff1a;彻底搞定Monaco Editor集成难题 【免费下载链接】monaco-editor A browser based code editor 项目地址: https://gitcode.com/gh_mirrors/mo/monaco-editor 你是否曾经在项目集成Monaco Editor时&#xff0c;满怀期待地复制粘贴示例…

作者头像 李华
网站建设 2026/6/10 9:36:57

Python开发者的终极Steam数据接入指南

Python开发者的终极Steam数据接入指南 【免费下载链接】steamapi An unofficial object-oriented Python library for accessing the Steam Web API. 项目地址: https://gitcode.com/gh_mirrors/st/steamapi 还在为复杂的Steam API对接而烦恼吗&#xff1f;steamapi库正…

作者头像 李华
网站建设 2026/6/9 20:54:54

3大维度深度解析:边缘AI语音部署中的算子优化实战

在嵌入式语音应用开发中&#xff0c;你是否曾因AI模型算子不兼容边缘设备而被迫重构方案&#xff1f;Sherpa-ONNX作为跨平台语音处理框架&#xff0c;在RK3588等边缘设备部署时面临的核心挑战正是算子兼容性问题。本文将突破传统技术文档框架&#xff0c;从内存管理、量化策略、…

作者头像 李华
网站建设 2026/6/10 11:14:36

5分钟搞定Steam游戏时长自动化:双工具对比实战全解析

还在为Steam游戏时长不足而苦恼吗&#xff1f;想要轻松收集交易卡却不想整天开着游戏占用系统资源&#xff1f;今天我要为你揭秘两款实用的Steam挂机工具&#xff0c;让你在无需实际运行游戏的情况下安全增加游戏时间。 【免费下载链接】HourBoostr Two programs for idling St…

作者头像 李华