UE4 对象类型Class及内存管理(1)

UE4中的对象在内存中的表示目前大概可分为三类:·

A、普通的C++类型 F Class

B、智能指针

C、UObject类型的UClass

我们逐一说明他们的使用方法和注意事项

1、针对普通的C++的class照普通的使用方式即可;UED中或者UE4的底层很多使用这种Class的例子;但UE4会统一的在前加F 比如:上次我们说的负责座标轴绘制和处理的FWidget类(在UnrealWidget.h中)

声明:

class FWidget
	: public FGCObject
{
FWidget();
}

使用:

FEditorViewportClient::FEditorViewportClient(FEditorModeTools* InModeTools, FPreviewScene* InPreviewScene, const TWeakPtr<SEditorViewport>& InEditorViewportWidget)
	: bAllowCinematicPreview(false)
...
, Widget(new FWidget)


销毁:

FEditorViewportClient::~FEditorViewportClient()
{
	...
	delete Widget;
}

目前大部分的F Class都在UED的框架中使用。在game的框架中相同功能的Class都改成了UClass

2、UE4的智能指针SmartPointer体系在引擎初期项目中用处主要在UI上;SlateUI是主要使用智能指针的地方。但随着后期UMG的出现SlateUI的部分被完全封装在UMG内部,现在研发人员一般不会接触到这一块。但对于研究引擎的人来说熟悉智能指针相当重要。以SWidget为例说明

声明方式():

class SLATECORE_API SWidget
	: public FSlateControlledConstruction,
	  public TSharedFromThis<SWidget>		// Enables 'this->AsShared()'
{
	friend struct FCurveSequence;
	//dubeibei XMod
	friend class UXScriptWidget;
public:
}

重点是类模版TSharedFromThis<SWidget>;TSharedPtr<>;TSharedRef<>

template< class ObjectType, ESPMode Mode >
class TSharedFromThis
{};

template< class ObjectType, ESPMode Mode >
class TSharedPtr
{};

template< class ObjectType, ESPMode Mode >
class TSharedRef
{};

template< class ObjectType, ESPMode Mode >
class TWeakPtr
{
public:
};


详情见:SharedPointer.h 其中指针会有SharedReferenceCount保存计数;计数为0时自动清理。TWeakPtr中有WeakReferenceCount保存计数,但TWeakPtr的引用计数不作为是否清理的标记,即TweakPtr中的Object可能已经被清理;但TweakPtr还在;可使用TWeakPtr的Isvalid来校验Object是否已被清理。

使用方式:

TSharedPtr<SWidget> RetWidget = SNew(SInvalidationPanel)

或者:

SAssignNew(MyTextBlock, STextBlock)

或者:

MakeShareable(new FUIController()); 返回的也是一个TSharedPtr

关于TSharedPtr TSharedRef TWeakPtr之间相互转换的使用:

TSharedPtr ToSharedRef()-> TSharedRef

TWeakPtr Pin()-> TSharedPtr

TSharedRef

转换使用StaticCastSharedPtr:

TSharedPtr<SChannelListPageWidget> MyWidget = StaticCastSharedPtr<SChannelListPageWidget>(GetWidget());

3、关于 UObject的Class使用

UObject是上层或者Game框架里面最经常用到的Class。把游戏框架中出现的各种东西抽象出一个UObject十分必要;通用的属性和接口;统一的GC;方便数据统计;等等

声明示例如下:

UCLASS(config = Game, meta = (ChildCanTick))
class PROJECTZ_API AMaterialParamaterObject : public AActor
{
	GENERATED_UCLASS_BODY()

	/** The CapsuleComponent being used for movement collision (by CharacterMovement). Always treated as being vertically aligned in simple collision check functions. */
	UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadOnly)
	class USceneComponent* RootSceneCom;

	/** The main skeletal mesh associated with this Character (optional sub-object). */
	UPROPERTY(Category = MapEditor, VisibleAnywhere, BlueprintReadOnly)
	class UStaticMeshComponent* Mesh;

	static FName MeshComponentName;
	static FName RootComponentName;

	UFUNCTION(BlueprintCallable, Category = "MapEditor|Objects")
	void ChangeFloatParamater(int32 ParaIndex, int32 NameIndex, float InValue);

	UFUNCTION(BlueprintCallable, Category = "MapEditor|Objects")
	void ChangeIntParamater(int32 ParaIndex, int32 NameIndex, int32 InValue);

	UFUNCTION(BlueprintCallable, Category = "MapEditor|Objects")
	void ChangeVectorParamater(int32 ParaIndex, int32 NameIndex, FVector InValue);

	UFUNCTION(BlueprintCallable, Category = "MapEditor|Objects")
	void ChangeTextureParamater(int32 ParaIndex, int32 NameIndex, UTexture2D* InValue);

	UPROPERTY(Category = "MapEditor|Objects", EditAnywhere, BlueprintReadWrite)
	TArray<FEditorMaterialParamater> Paramaters;

};

关于UHT:UnrealHeaderTool,UHT会根据UClass的头文件.h生成.generated.h文件把其中拥有UPROPERTY UFUNCTION的标签的重新定义例如ChangeFloatParamater接口:

DECLARE_FUNCTION(execChangeFloatParamater) \
	{ \
		P_GET_PROPERTY(UIntProperty,Z_Param_ParaIndex); \
		P_GET_PROPERTY(UIntProperty,Z_Param_NameIndex); \
		P_GET_PROPERTY(UFloatProperty,Z_Param_InValue); \
		P_FINISH; \
		P_NATIVE_BEGIN; \
		this->ChangeFloatParamater(Z_Param_ParaIndex,Z_Param_NameIndex,Z_Param_InValue); \
		P_NATIVE_END; \

	}



新生成的.genreated.h文件会加入编译所有的UPROPERTY和UFUNCTION都会是继承自UObject的Class使用 ;然后再由GC统一的管理UObject;

不加UPROPETY标签的属性不在UObject 此过程GC的范围之内;需要另外的控制,不然很容易内存泄漏。见下章详细说明。

使用:

MyGCProtectedObj = NewObject<UMyObjectClass>(this);
如果不想让UObject强制回收可设置:
YourObjectInstance->AddToRoot();

销毁:

if(!MyObject) return;
if(!MyObject->IsValidLowLevel()) return;
 
MyObject->ConditionalBeginDestroy(); //instantly clears UObject out of memory
MyObject = nullptr;

销毁Actor:
if(!TheCharacter) return;
if(!TheCharacter->IsValidLowLevel()) return;
TheCharacter->Destroy();
TheCharacter->ConditionalBeginDestroy(); //essential extra step, in all my testing

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章