Smart Pointers vs Raw
TWeakObjectPtr, TSoftObjectPtr, TObjectPtr์ GC ํน์ฑ๊ณผ ์ ์ ํ ์ฌ์ฉ ์์ ์ ์ดํดํฉ๋๋ค
TObjectPtr - UE5์ ์๋ก์ด ๊ธฐ๋ณธ ํฌ์ธํฐ
raw UObject*๋ฅผ ๋์ฒดํ๋ UE5์ ์ค๋งํธ ํฌ์ธํฐ
TObjectPtr<T>
UE5์์ ๋์
๋ TObjectPtr<T>๋ UPROPERTY์์ raw UObject*๋ฅผ ๋์ฒดํฉ๋๋ค. ์๋ํฐ ๋น๋์์๋ ์ง์ฐ ๋ก๋ฉ๊ณผ ์ ๊ทผ ์ถ์ ์ ์ ๊ณตํ๊ณ , ์ฌํ ๋น๋์์๋ raw ํฌ์ธํฐ์ ๋์ผํ ์ฑ๋ฅ์ ๋ณด์
๋๋ค.
UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
// UE5 ๋ฐฉ์ (๊ถ์ฅ)
UPROPERTY()
TObjectPtr<UStaticMeshComponent> MeshComp;
// UE4 ๋ ๊ฑฐ์ ๋ฐฉ์
UPROPERTY()
UStaticMeshComponent* OldStyleComp;
// TObjectPtr๋ ์๋์ผ๋ก T*๋ก ๋ณํ๋จ
void UseComponent()
{
MeshComp->SetRelativeLocation(FVector::ZeroVector);
// raw ํฌ์ธํฐ์ ๋์ผํ๊ฒ ์ฌ์ฉ
UStaticMeshComponent* RawPtr = MeshComp.Get();
// ๋๋ ์์์ ๋ณํ
UStaticMeshComponent* RawPtr2 = MeshComp;
}
};
TObjectPtr์ GC ํน์ฑ
| ํน์ฑ | TObjectPtr | Raw UObject* |
|---|---|---|
| GC ์ฐธ์กฐ ์ถ์ | ๊ฐํ ์ฐธ์กฐ (UPROPERTY) | ๊ฐํ ์ฐธ์กฐ (UPROPERTY) |
| ์ฐ๊ธฐ ๋ฐฐ๋ฆฌ์ด | ์ง์ (Incremental GC) | ๋ฏธ์ง์ |
| MarkAsGarbage ์๋ ์ฒ๋ฆฌ | null์ฒ๋ผ ๋์ | ์๋ ํ์ธ ํ์ |
| ์ง์ฐ ๋ก๋ฉ (์๋ํฐ) | ์ง์ | ๋ฏธ์ง์ |
| ์ฌํ ๋น๋ ์ค๋ฒํค๋ | ์์ (raw์ ๋์ผ) | - |
TWeakObjectPtr - ์ฝํ ์ฐธ์กฐ
GC๋ฅผ ๋ฐฉํดํ์ง ์๋ ์์ ํ ์ฐธ์กฐ ๋ฐฉ์
TWeakObjectPtr<T>
TWeakObjectPtr์ ๊ฐ์ฒด๋ฅผ GC๋ก๋ถํฐ ๋ณดํธํ์ง ์๋ ์ฝํ ์ฐธ์กฐ์
๋๋ค. ๋์ ๊ฐ์ฒด๊ฐ GC๋๋ฉด ์๋์ผ๋ก null์ด ๋ฉ๋๋ค. ๋ด๋ถ์ ์ผ๋ก GUObjectArray์ ์ธ๋ฑ์ค์ SerialNumber๋ฅผ ์ฌ์ฉํฉ๋๋ค.
// TWeakObjectPtr ์ฌ์ฉ๋ฒ
TWeakObjectPtr<AActor> WeakActor;
// ํ ๋น
WeakActor = SomeActor;
// ์ ํจ์ฑ ๊ฒ์ฌ (ํต์ฌ!)
if (WeakActor.IsValid())
{
AActor* Actor = WeakActor.Get();
Actor->DoSomething();
}
// GC๊ฐ SomeActor๋ฅผ ์์งํ ํ
check(!WeakActor.IsValid()); // true - ์๋์ผ๋ก ๋ฌดํจํ
check(WeakActor.Get() == nullptr); // true
// UPROPERTY๋ก ์ ์ธ ์์๋ GC ๋ณดํธ ์ ํจ
UPROPERTY()
TWeakObjectPtr<AActor> WeakRef; // ์ฝํ ์ฐธ์กฐ ์ ์ง
UPROPERTY๋ก ์ ์ธ๋ TWeakObjectPtr๋ GC ํ ํฐ ์คํธ๋ฆผ์์ ์ฝํ ์ฐธ์กฐ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค. ์ฆ, UPROPERTY()๊ฐ ์์ด๋ ๋์ ๊ฐ์ฒด๋ฅผ GC๋ก๋ถํฐ ๋ณดํธํ์ง ์์ต๋๋ค. ์ด๋ UObject*์ ๊ฒฐ์ ์ ์ผ๋ก ๋ค๋ฅธ ์ ์
๋๋ค.
TSoftObjectPtr - ์ํํธ ์ฐธ์กฐ
์์ ๊ฒฝ๋ก ๊ธฐ๋ฐ์ ์ง์ฐ ๋ก๋ฉ ์ฐธ์กฐ
TSoftObjectPtr<T>
TSoftObjectPtr์ ์์
์ ๊ฒฝ๋ก(FSoftObjectPath)๋ฅผ ์ ์ฅํฉ๋๋ค. ์์
์ด ๋ฉ๋ชจ๋ฆฌ์ ์์ด๋ ๊ฒฝ๋ก๋ ์ ํจํ๋ฉฐ, ํ์ ์ ๋ช
์์ ์ผ๋ก ๋ก๋ํฉ๋๋ค. GC ๊ด์ ์์ ๋์ ์์
์ ๋ณดํธํ์ง ์์ผ๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์
๋๋ค.
UCLASS()
class UInventoryItem : public UObject
{
GENERATED_BODY()
// ์์ด์ฝ์ ํ์ํ ๋๋ง ๋ก๋
UPROPERTY(EditAnywhere)
TSoftObjectPtr<UTexture2D> Icon;
// ๋ฉ์๋ ํ์ํ ๋๋ง ๋ก๋
UPROPERTY(EditAnywhere)
TSoftObjectPtr<UStaticMesh> Mesh;
UTexture2D* GetIcon()
{
// ๋๊ธฐ ๋ก๋ (๋ก๋๋์ง ์์์ผ๋ฉด ๋ก๋)
return Icon.LoadSynchronous();
}
void LoadMeshAsync()
{
// ๋น๋๊ธฐ ๋ก๋
FStreamableManager& SM = UAssetManager::GetStreamableManager();
SM.RequestAsyncLoad(
Mesh.ToSoftObjectPath(),
FStreamableDelegate::CreateUObject(
this, &UInventoryItem::OnMeshLoaded)
);
}
};
ํฌ์ธํฐ ํ์ ๋ณ GC ๋์ ๋น๊ต
| ํ์ | GC ๋ณดํธ | ์์ ๋ก๋ | null ์์ | ์ฌ์ฉ ์์ |
|---|---|---|---|---|
TObjectPtr<T> | ๊ฐํ | ์ฆ์ | Garbage ์๋ ์ฒ๋ฆฌ | ๊ธฐ๋ณธ ์ฐธ์กฐ |
UObject* | ๊ฐํ | ์ฆ์ | ์๋ ํ์ธ | ๋ ๊ฑฐ์/๋ก์ปฌ |
TWeakObjectPtr | ์์ | ์ฆ์ | IsValid() ์ฒดํฌ | ์บ์, ๊ด์ฐฐ |
TSoftObjectPtr | ์์ | ์ง์ฐ | ๊ฒฝ๋ก๋ง ์ ํจ | ์์ ์ฐธ์กฐ |
TSoftClassPtr | ์์ | ์ง์ฐ | ๊ฒฝ๋ก๋ง ์ ํจ | ํด๋์ค ์ฐธ์กฐ |
Non-UObject ์ค๋งํธ ํฌ์ธํฐ
TSharedPtr, TUniquePtr๋ GC์ ๋ฌด๊ดํ ๋ณ๋ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
GC ์ธ๋ถ์ ์ค๋งํธ ํฌ์ธํฐ
UE5์๋ GC์ ๋ฌด๊ดํ C++ ์คํ์ผ ์ค๋งํธ ํฌ์ธํฐ๋ ์์ต๋๋ค. ์ด๋ค์ Non-UObject์ ์ฌ์ฉ๋๋ฉฐ, ์ฐธ์กฐ ์นด์ดํ ์ด๋ ์ ๋ํฌ ์์ ๊ถ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
// TSharedPtr - ์ฐธ์กฐ ์นด์ดํ
(Non-UObject ์ ์ฉ)
TSharedPtr<FMyData> SharedData = MakeShared<FMyData>();
// ์ฐธ์กฐ ์นด์ดํธ๊ฐ 0์ด ๋๋ฉด ์๋ ํด์
// UObject์ ์ฌ์ฉํ๋ฉด ์ ๋จ! (์ด์ค ํด์ ์ํ)
// TWeakPtr - TSharedPtr์ ์ฝํ ๋ฒ์
TWeakPtr<FMyData> WeakData = SharedData;
// TUniquePtr - ์ ์ผํ ์์ ๊ถ
TUniquePtr<FMyData> UniqueData = MakeUnique<FMyData>();
// ์์ ์๊ฐ ํ๊ดด๋๋ฉด ์๋ ํด์
// ์๋ชป๋ ์ฌ์ฉ: UObject์ TSharedPtr ์ฌ์ฉ
// TSharedPtr<UMyObject> Bad = ...; // ์ ๋ ํ์ง ๋ง์ธ์!
// GC์ ์ฐธ์กฐ ์นด์ดํ
์ด ์ถฉ๋ํ์ฌ ํฌ๋์ ๋ฐ์
UObject์ ์๋ช
์ GC๊ฐ ๊ด๋ฆฌํฉ๋๋ค. TSharedPtr์ ์ฐธ์กฐ ์นด์ดํ
๊ณผ GC์ ๋๋ฌ ๊ฐ๋ฅ์ฑ ๋ถ์์ด ์ถฉ๋ํ์ฌ ์ด์ค ํด์ (double free)๋ ๋๊ธ๋ง ํฌ์ธํฐ๊ฐ ๋ฐ์ํฉ๋๋ค. UObject์๋ ๋ฐ๋์ TObjectPtr, TWeakObjectPtr, TSoftObjectPtr๋ฅผ ์ฌ์ฉํ์ธ์.
ํต์ฌ ์์ฝ
- TObjectPtr๋ UE5์ ์ ๊ธฐ๋ณธ ํฌ์ธํฐ๋ก, ์ฐ๊ธฐ ๋ฐฐ๋ฆฌ์ด์ MarkAsGarbage ์๋ ์ฒ๋ฆฌ๋ฅผ ์ ๊ณตํฉ๋๋ค
- TWeakObjectPtr๋ GC๋ฅผ ๋ฐฉํดํ์ง ์๋ ์ฝํ ์ฐธ์กฐ๋ก, ์บ์๋ ๊ด์ฐฐ ํจํด์ ์ ํฉํฉ๋๋ค
- TSoftObjectPtr๋ ์์ ๊ฒฝ๋ก ๊ธฐ๋ฐ ์ง์ฐ ๋ก๋ฉ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค
- TSharedPtr/TUniquePtr๋ Non-UObject ์ ์ฉ์ด๋ฉฐ, UObject์ ์ฌ์ฉํ๋ฉด ์ ๋ฉ๋๋ค
- ์ฌ๋ฐ๋ฅธ ํฌ์ธํฐ ์ ํ์ด GC ํจ์จ๊ณผ ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ์ ๋ชจ๋ ๊ฒฐ์ ํฉ๋๋ค
๋์ ๊ณผ์
๋ฐฐ์ด ๋ด์ฉ์ ์ง์ ์ค์ตํด๋ณด์ธ์
TSharedPtr๊ณผ TWeakPtr๋ก ์ผ๋ฐ C++ ๊ฐ์ฒด๋ฅผ ๊ด๋ฆฌํ๋ ์ฝ๋๋ฅผ ์์ฑํ์ธ์. ์ฐธ์กฐ ์นด์ดํธ ๋ณํ๋ฅผ ๋ก๊ทธ๋ก ์ถ์ ํ๊ณ , TWeakPtr::IsValid()๊ฐ false๊ฐ ๋๋ ์์ ์ ํ์ธํ์ธ์. UObject์๋ TSharedPtr์ ์ฌ์ฉํ๋ฉด ์ ๋๋ ์ด์ ๋ฅผ ์ฝ๋๋ก ์ฆ๋ช ํ์ธ์.
TWeakObjectPtr๋ก AActor๋ฅผ ์ฐธ์กฐํ๊ณ , Actor๋ฅผ Destroyํ ํ TWeakObjectPtr::IsValid()์ TWeakObjectPtr::Get()์ ๋ฐํ๊ฐ์ ํ์ธํ์ธ์. GC ์ ํ์ ๋์ ์ฐจ์ด์ raw pointer ๋๋น ์์ ์ฑ์ ํ ์คํธํ์ธ์.
TObjectPtr, TWeakObjectPtr, TSoftObjectPtr, raw pointer์ ์ ๊ทผ ์๋๋ฅผ 100,000ํ ๋ฐ๋ณต ์ ๊ทผ์ผ๋ก ๋ฒค์น๋งํฌํ์ธ์. FPlatformTime::Seconds()๋ก ์๊ฐ์ ์ธก์ ํ๊ณ , ๊ฐ ํฌ์ธํฐ ํ์ ์ ์ค๋ฒํค๋๋ฅผ ์ ๋์ ์ผ๋ก ๋น๊ตํ์ธ์.