UE_C++ —— Unreal Smart Pointer Library

目录

一,Smart Pointer Types

二,Benefits of Smart Pointers

三,Helper Classes and Functions

四,智能指针实现细节

Speed

Intrusive Accessors

Casting

Thread Safety

五,提示和限制


        虚幻智能指针库 为C++11智能指针的自定义实现,旨在减轻内存分配和追踪的负担;该实现包括行业标准 共享指针(Shared Pointers)弱指针(Weak Pointers) 和 唯一指针(Unique Pointers);其还可添加 共享引用(Shared References),此类引用的行为与不可为空的共享指针相同;虚幻Objects使用更适合游戏代码的单独内存追踪系统,因此这些类无法与 UObject 系统同时使用;

一,Smart Pointer Types

        智能指针可影响其包含或引用对象的寿命,不同智能指针对对象有不同的限制和影响;

Shared Pointers

(TSharedPtr)

共享指针拥有其引用的对象,无限防止该对象被删除,并在无共享指针或共享引用(见下文)引用其时,最终处理其的删除;

共享指针可为空,意味其不引用任何对象;任何非空共享指针都可对其引用的对象生成共享引用;

Shared References

(TSharedRef)

共享引用的行为与共享指针类似,即其拥有引用的对象;对于空对象而言,其存在不同;共享引用须总是引用非空对象;共享指针无此类限制,因此共享引用可转换为共享指针,且该共享指针引用有效对象;要确认引用的对象是非空,或者要表明共享对象所有权时,请使用共享引用;

Weak Pointers

(TWeakPtr)

弱指针类与共享指针类似,但不拥有其引用的对象,因此不影响其生命周期;此属性中断引用循环,因此十分有用,但也意味弱指针可在无预警的情况下随时变为空;因此,弱指针可生成指向其引用对象的共享指针,确保程序员能对该对象进行安全临时访问;

Unique Pointers 

(TUniquePtr)

唯一指针仅会显式拥有其引用的对象;仅有一个唯一指针指向给定资源,因此唯一指针可转移所有权,但无法共享;复制唯一指针的任何尝试都将导致编译错误;唯一指针超出范围时,其将自动删除其所引用的对象;

注,对唯一指针引用的对象进行共享指针或共享引用的操作十分危险;即使其他智能指针继续引用该对象,此操作不会取消唯一指针自身被销毁时删除该对象的行为;同样,不应为共享指针或共享引用引用的对象创建唯一指针;

二,Benefits of Smart Pointers

防止内存泄漏共享引用不存在时,智能指针(弱指针除外)会自动删除对象;
弱引用弱指针会中断引用循环并阻止悬挂指针;
可选择的线程安全能指针库包括线程安全代码,可跨线程管理引用计数;如无需线程安全,可用其换取更好性能;
运行时安全共享引用从不为空,可随时取消引用;
传达意图可轻松区分对象所有者和观察者;
内存智能指针在64位下仅为C++指针大小的两倍(加上共享的16字节引用控制器);唯一指针除外,其与C++指针大小相同;

三,Helper Classes and Functions

        虚幻智能指针库提供多个助手类和函数,以便使用智能指针时更加容易、直观;

Classes
TSharedFromThis从TSharedFromThis派生类,添加AsShared or SharedThis函数;此类函数可获取对象的 TSharedRef
Functions
MakeSharedMakeShareable

在常规C++指针中创建共享指针;

MakeShared 会在单个内存块中分配新的对象实例和引用控制器,但要求对象提交public构造函数;

MakeShareable 的效率较低,但即使对象的构造函数为私有,其仍可运行;利用此操作可拥有非自己创建的对象,并在删除对象时支持自定义行为;

StaticCastSharedRefStaticCastSharedPtr静态投射效用函数,通常用于向下投射到派生类型;
ConstCastSharedRefConstCastSharedPtr将 const 智能引用或智能指针分别转换为 mutable 智能引用或智能指针;

四,智能指针实现细节

        在功能和效率方面,虚幻智能指针库中的智能指针具有一些共同特征;

Speed

        要使用智能指针时,始终考虑性能;智能指针非常适合某些高级系统、资源管理或工具编程;但部分智能指针类型比原始C++指针更慢,这种开销使得其在低级引擎代码(如渲染)中用处不大;

智能指针的部分性能优势包括:

  • 所有运算均为常量时间;
  • 取消引用多数智能指针的速度和原始C++指针的相同(在发布版本中);
  • 复制智能指针不会分配内存;
  • 线程安全智能指针是无锁的;

智能指针的性能缺陷包括:

  • 创建和复制智能指针比创建和复制原始C++指针需要更多开销;
  • 保持引用计数增加基本运算的周期;
  • 部分智能指针占用的内存比原始的C++更多;
  • 引用控制器有两个堆分配;使用 MakeShared 代替 MakeShareable 可避免二次分配,并可提高性能;
Intrusive Accessors

        共享指针是non-intrusive,意味对象不知道其是否为智能指针拥有;此通常是可以接受的,但在某些情况下,可能要将对象作为共享引用或共享指针进行访问;为此,使用对象的类作为模板参数,从 TSharedFromThis 派生对象的类;TSharedFromThis 提供两个函数:AsShared 和 SharedThis,可将对象转换为共享引用(并从共享引用转换为共享指针);使用固定返回共享引用的类factory时,或需将对象传到需要共享引用或共享指针的系统时,此操作十分有用;AsShared 会将类返回为最初作为模板参数传到 TSharedFromThis 的类型返回,其可能是调用对象的父类型,而 SharedThis 将直接从该类型衍生类型,并返回引用该类型对象的智能指针;

class FRegistryObject;
	class FMyBaseClass: public TSharedFromThis<FMyBaseClass>
	{
		virtual void RegisterAsBaseClass(FRegistryObject* RegistryObject)
		{
			// Access a shared reference to 'this'.
			// We are directly inherited from <TSharedFromThis> , so AsShared() and SharedThis(this) return the same type.
			TSharedRef<FMyBaseClass> ThisAsSharedRef = AsShared();
			// RegistryObject expects a TSharedRef<FMyBaseClass>, or a TSharedPtr<FMyBaseClass>. TSharedRef can implicitly be converted to a TSharedPtr.
			RegistryObject->Register(ThisAsSharedRef);
		}
	};
	class FMyDerivedClass : public FMyBaseClass
	{
		virtual void Register(FRegistryObject* RegistryObject) override
		{
			// We are not directly inherited from TSharedFromThis<>, so AsShared() and SharedThis(this) return different types.
			// AsShared() will return the type originally specified in TSharedFromThis<> - TSharedRef<FMyBaseClass> in this example.
			// SharedThis(this) will return a TSharedRef with the type of 'this' - TSharedRef<FMyDerivedClass> in this example.
			// The SharedThis() function is only available in the same scope as the 'this' pointer.
			TSharedRef<FMyDerivedClass> AsSharedRef = SharedThis(this);
			// RegistryObject will accept a TSharedRef<FMyDerivedClass> because FMyDerivedClass is a type of FMyBaseClass.
			RegistryObject->Register(ThisAsSharedRef);
		}
	};
	class FRegistryObject
	{
		// This function will accept a TSharedRef or TSharedPtr to FMyBaseClass or any of its children.
		void Register(TSharedRef<FMyBaseClass>);
	};

不要在构造函数中调用 AsShared 或 Shared,共享引用此时并未初始化,将导致崩溃或断言;

Casting

        可通过虚幻智能指针库包含的多个支持函数cast共享指针(和共享引用);Up-casting是隐式的,与C++指针相同;可使用 ConstCastSharedPtr 函数进行const cast,使用 StaticCastSharedPtr 进行static cast(通常是downcast到派生类指针);无run-type类型的信息(RTTI),因此不支持动态转换;

// This assumes we validated that the FDragDropOperation is actually an FAssetDragDropOp through other means.
TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();
// We can now cast with StaticCastSharedPtr.
TSharedPtr<FAssetDragDropOp> DragDropOp = StaticCastSharedPtr<FAssetDragDropOp>(Operation);
Thread Safety

        通常仅在单线程上访问智能指针的操作才是安全的。如需访问多线程,请使用智能指针类的线程安全版本:

  • TSharedPtr<T, ESPMode::ThreadSafe>

  • TSharedRef<T, ESPMode::ThreadSafe>

  • TWeakPtr<T, ESPMode::ThreadSafe>

  • TSharedFromThis<T, ESPMode::ThreadSafe>

由于原子引用计数,此类线程安全版本比默认版本稍慢,但其行为与常规C++指针一致:

  • 读取和复制固定为线程安全;

  • 写入和重置须同步后才安全;

注,如多线程永不访问指针,可通过避免使用线程安全版本获得更好性能;

五,提示和限制

  • 避免将数据作为 TSharedRef 或 TSharedPtr 参数传到函数,此操作将因取消引用和引用计数而产生开销;相反,建议将引用对象作为 const & 进行传递;

  • 可将共享指针向前声明为不完整类型;

  • 共享指针与虚幻对象(UObject 及其派生类)不兼容;引擎具有 UObject 管理的单独内存管理系统,两个系统未互相重叠;

LoginId:0c02195c44627f550138648786ba31c0 EpicAccountId:599c1d2c5b7c4311b5e6a941fdf587f9 Assertion failed: ItemSelected.IsValid() [File:D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\Fbx\SSceneReimportStaticMeshListView.cpp] [Line: 423] UnrealEditor_UnrealEd UnrealEditor_UnrealEd UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_UnrealEd UnrealEditor_SlateCore UnrealEditor_Slate UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_Slate UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_Slate UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_Slate UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_Slate UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_SlateCore UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_UnrealEd UnrealEditor_UnrealEd UnrealEditor_UnrealEd UnrealEditor_UnrealEd UnrealEditor_UnrealEd UnrealEditor_ContentBrowserAssetDataSource UnrealEditor_ContentBrowserAssetDataSource UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_Slate UnrealEditor_ApplicationCore UnrealEditor_ApplicationCore UnrealEditor_ApplicationCore UnrealEditor_ApplicationCore user32 user32 UnrealEditor_ApplicationCore UnrealEditor UnrealEditor UnrealEditor UnrealEditor UnrealEditor UnrealEditor kernel32 ntdll
最新发布
09-20
<think> 我们正在处理一个Unreal Engine编辑器中的断言错误。错误信息为: Assertion failed: ItemSelected.IsValid() [File:D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\Fbx\SSceneReimportStaticMeshListView.cpp] [Line: 423] 这个错误通常发生在重新导入静态网格体(Static Mesh)时,特别是在使用FBX重新导入的场景中。从文件路径类名(SSceneReimportStaticMeshListView)可以推断,这个断言错误发生在场景重新导入静态网格体列表视图的代码中。 断言失败是因为代码期望一个有效的选中项(ItemSelected.IsValid()),但实际上选中项无效。这通常意味着在用户界面操作中,代码试图访问一个不存在的选中项。 可能的原因解决方案: 1. **重新导入操作未正确选择网格体**: - 当你在内容浏览器中选择静态网格体资产进行重新导入时,如果选择无效(例如,没有选中任何网格体,或者选中的对象不是静态网格体),可能会触发此错误。 - **解决方案**:确保在内容浏览器中正确选中一个或多个静态网格体资产,然后右键选择“重新导入”。 2. **重新导入操作被取消或中断**: - 如果在重新导入过程中用户取消了操作,或者由于某些原因操作被中断,可能会导致内部状态不一致。 - **解决方案**:尝试重新启动Unreal Editor,然后再次执行重新导入操作。 3. **编辑器版本问题**: - 此错误可能是特定版本的Unreal Engine的bug。特别是,错误发生在`SSceneReimportStaticMeshListView.cpp`中,这个类用于处理FBX重新导入时的场景列表视图。 - **解决方案**:检查你的引擎版本是否有已知的修复。可以尝试升级到最新版本或修复版本。 4. **损坏的静态网格体资产**: - 如果某个静态网格体资产损坏,可能会导致在重新导入时出现断言错误。 - **解决方案**:尝试单独重新导入该静态网格体资产,或者创建一个新的静态网格体资产替换它。 5. **插件冲突**: - 某些插件可能会干扰重新导入流程。 - **解决方案**:禁用最近安装的插件,特别是与导入/导出相关的插件,然后重试。 6. **手动修复(高级用户)**: - 如果以上方法无效,可以尝试在引擎源代码中定位这个断言,并查看上下文以理解具体原因。但是,这需要你拥有引擎源码并能够编译引擎。 由于错误发生在编辑器代码中,且涉及到用户界面操作,我们无法通过脚本直接修改内部状态。因此,主要解决方案集中在操作步骤避免触发条件上。 下面是具体的解决步骤: **步骤1:检查选择状态** - 在内容浏览器中,确保你选中了一个或多个静态网格体资产(高亮显示)。 - 右键点击选中的资产,选择“重新导入”(Reimport)。 **步骤2:重启编辑器** - 关闭当前项目,然后重新打开Unreal Editor。 - 再次尝试重新导入操作。 **步骤3:更新引擎** - 如果你使用的是源码版本,尝试更新到最新代码并重新编译。 - 如果使用的是Epic启动器版本,尝试更新到最新版本。 **步骤4:逐个重新导入** - 如果批量重新导入多个静态网格体时出现错误,尝试单独重新导入每个网格体,以确定是哪个网格体导致的问题。 **步骤5:检查FBX文件** - 确保原始FBX文件没有损坏,并且路径正确(如果重新导入时提示选择源文件,确保选择正确的文件)。 **步骤6:创建新项目测试** - 创建一个新的空白项目,将静态网格体导入到新项目中,观察是否出现同样错误。如果新项目中没有错误,说明原项目可能存在损坏或配置问题。 如果以上步骤都无法解决,可能需要向Unreal Engine社区或Epic技术支持提交问题报告,并提供重现步骤。 注意:这个断言错误通常不会影响游戏运行,它只是一个编辑器错误,主要影响重新导入操作。 §§相关问题§§ 1. Unreal Engine中如何批量重新导入静态网格体而不触发断言错误? 2. Unreal Engine编辑器断言错误的通用排查方法是什么? 3. 如何修复Unreal Engine中损坏的静态网格体资产? </think> ### 解决虚幻引擎断言错误 `Assertion failed: ItemSelected.IsValid()` 的完整方案 这个错误通常发生在重新导入静态网格体时,具体位于场景重新导入列表视图的逻辑中(`SSceneReimportStaticMeshListView.cpp`)。以下是系统化的解决方案: #### 1. **核心修复步骤** 1. **验证资产选择状态** - 在内容浏览器中**手动重新选择**需要操作的静态网格体资产 - 确保选择对象是**有效静态网格体**(非蓝图、材质等其他类型资产) - 避免使用Ctrl+A全选(可能包含无效项) 2. **重启编辑器清理缓存** ```mermaid graph TD A[关闭UE编辑器] --> B[删除以下文件夹] B --> C[Saved/AssetRegistry] B --> D[Saved/Config] B --> E[Intermediate] C --> F[重新启动UE] ``` 3. **更新导入选项配置** 打开 `编辑 > 项目设置 > 导入设置`: - 取消勾选 **"自动检测导入类型"** - 禁用实验性功能(如"异步导入") - 重置静态网格体默认设置 #### 2. **代码层解决方案** 1. **修复引擎源码(需源码版本)** 修改 `SSceneReimportStaticMeshListView.cpp` 第423行附近: ```cpp // 原断言代码 check(ItemSelected.IsValid()); // 修改为安全校验 if (!ItemSelected.IsValid()) { UE_LOG(LogTemp, Warning, TEXT("Invalid selection in reimport flow")); return FReply::Handled(); } ``` 2. **Python批量修复脚本** ```python import unreal def safe_reimport(asset_path): try: asset = unreal.load_asset(asset_path) if asset and asset.is_a(unreal.StaticMesh.static_class()): unreal.EditorAssetLibrary.reimport_asset(asset_path) except Exception as e: unreal.log_error(f"Reimport failed for {asset_path}: {str(e)}") # 示例:修复Content/Meshes目录 assets = unreal.EditorAssetLibrary.list_assets("/Game/Meshes") [safe_reimport(a) for a in assets if a.endswith(".uasset")] ``` #### 3. **高级故障排除** 1. **诊断资产依赖关系** - 使用 **Reference Viewer** (右键资产 > 引用查看器) - 检查是否存在循环引用或损坏的父级蓝图 - 修复方法:`右键资产 > 重构 > 修复重定向器` 2. **FBX导入器深度修复** ```mermaid sequenceDiagram 用户->>FBX导入器: 发起重新导入 FBX导入器->>场景列表: 请求选择状态 场景列表-->>FBX导入器: 返回ItemSelected 错误分支->>断言: ItemSelected无效 正确分支->>导入管道: 执行重新导入 ``` - 解决方案链: $$ \text{清理资产} \rightarrow \text{重置选择状态} \rightarrow \text{重建导入管道} $$ #### 4. **预防性措施** 1. **项目配置优化** 在 `DefaultEngine.ini` 添加: ```ini [ReimportSettings] bEnableSelectionValidation=True SelectionValidationThreshold=0.5 ``` 2. **版本控制规范** - 在重新导入前提交所有更改 - 使用 `git lfs lock` 锁定相关资产 - 避免在未加载完资产时操作编辑器 > **验证效果**:修复后重新导入时,控制台应显示: > `LogStaticMeshEditor: Reimport completed for /Game/Meshes/Rock_01` > 而非断言错误[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值