- this post covers
- what is unique pointer in unreal engine
- how it is used
- restriction and caution on usage
- environment
- Unreal Engine (4.24)
- Visual Studio 2017
- Windows 10
- reference
overview
as unreal engine handles objects inherits UObject
, we can use unreal engine easily. there are several benefits when the object inherits UObject
.
- garbage collection
- reference update
- reflection
- serialization
- etc.
then you might have one question,
“how we can handle the objects does not inherit UObject
? should we use raw pointer for the objects ?”
well…there are 2 ways for this.
- using
std::unique_ptr
of cpp std library inmemory.h
- using
TUniquePtr
of unreal API inUniquePtr.h
you can use std::unique_ptr
in unreal project, but unreal engine implements their own smart pointer library. and it is common that using TUniquePtr
in unreal project unless you do not need cpp std library.
as purpose and functionality are the same, TUniquePtr
is similar to std::unique_ptr
. TUniquePtr
also provides the unique ownership and other features. let us check out what it is and how it is used.
built-in example
you can find some example in unreal engine code.
1 | UnrealEngine/Engine/Source/Runtime/SandboxFile/Public/IPlatformFileSandboxWrapper.h |
class FSandboxPlatformFile
is not a class inherits UObject
and it is possible to be indicated with TUniquePtr
.
( conventionally, prefix U
is attached when the class inherits UObject
)
1 | UnrealEngine/Engine/Source/Editor/UnrealEd/Classes/CookOnTheSide/CookOnTheFlyServer.h |
class UCookOnTheFlyServer
is a class inhertis UObject
and it contains TUniquePtr
with FSandboxPlatformFile
as member variable.
1 | UnrealEngine/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp |
accessing the object through TUniquePtr
is the same on std::unique_ptr
. using ->
operator, you can access the object as the normal pointer.
1 | UnrealEngine/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp |
validation on TUniquePtr
is the same on raw pointer. if the value is zero, the TUniquePtr
is pointing nullptr
. you can use check
for ensuring whether the TUniquePtr
is valid.
1 | UnrealEngine/Engine/Source/Editor/UnrealEd/Private/Commandlets/AssetRegistryGenerator.cpp |
FAssetRegistryGenerator::SaveManifests
gets FSandboxPlatformFile*
as one of parameters. the type of parameter is not the TUniquePtr
, so we should convert TUniquePtr<T>
into T*
.
1 | UnrealEngine/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp |
use the TUniquePtr::Get()
if you need the raw pointer of TUniquePtr<T>
.
1 | UnrealEngine/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp |
assigning nullptr
into TUniquePtr
, you can let TUniquePtr
release the object and have its value as nullptr
.
1 | UnrealEngine/Engine/Source/Runtime/SandboxFile/Public/IPlatformFileSandboxWrapper.h |
constructor of FSandboxPlatformFile
takes one parameter as boolean.
1 | UnrealEngine/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp |
MakeUnique
returns TUniquePtr
object and calls the constructor of the template class. in this case, MakeUnique<FSandboxPlatformFile>
takes one boolean value.
restriction and caution
suppose you have a class like below
1 | class UserInfo |
you should only use TUniquePtr
at the object, which exists only one thing. unless, you would get an exception for delete on nullptr
.
1 | void SomeUActor::BeginPlay() |
in this code, CreateUserInformation
will be called in BeginPlay
and ReleaseUserInformation
will be called in EndPlay
. UserInformation
is a memeber variable with TUniquePtr<UserInfo>
type. another TUniquePtr<UserInfo>
exists in CreateUserInformation
, which gets UserInfo*
.
what happens when CreateUserInformation
is ended ? AnotherPtr
would disappear and its destructor would be called. when the destructor of TUniquePtr
is called, it releases memory that TUniquePtr
has pointed. as a result, variable UserInformation
would be a dangling pointer.
UserInformation
has abnormal values.
because already the memory is released, an exception would be thrown when we execute ReleaseUserInformation
. it is why you have to use TUniquePtr
at the object only existing one thing and care about moving the ownership. moving the ownership with raw pointer is dangerous as we have seen.
1 | void SomeUActor::CreateUserInformation() |
let us move the ownership with MoveTemp
API. this code makes AnotherPtr
point the memory and UserInformation
set the nullptr
.
UserInformation
has nullptr
. so we can avoid the exception.
summary
TUniquePtr
is similar to std::unique_ptr
and its usage and restriction, too.
- initialization: you can initialize
TUniquePtr
with 2 ways
type | method |
---|---|
using raw pointer | TUniquePtr<T> PointerA(T*); |
using other TUniquePtr |
TUniquePtr<T> PointerA(MoveTemp(PointerB)); |
- transfering ownership: for preventing side effect, you should use
MoveTemp
1 | TUniquePtr<T> PointerA = new T(...); |
- release: there are various ways to release the
TUniquePtr
1 | // way #1 : release implicitly |