UE4/C++: NewObject で生成したオブジェクトの Outer を変更したい場合のメモ
↓こういうのが居たとする。
// UObject 派生だがシングルトンファクトリーで生成されるオブジェクトがあったとする UA* UA::GetInstance() { if ( ! my_static_instance ) my_static_instance = NewObject< UA >(); return my_static_instance; }
このようなファクトリーで得られる仕組みの UA
のオブジェクトは Outer
を持たないため GetWorld()
しても nullptr
が帰るなど不便な事もある。幾つか無理やり気味な方法は思いつくものの、 Outer
を外から設定できてしまえば何かと解決する。この悩み事が生じた際は UObject::Rename
が最も簡単な解決方法になる事がある。
// UGameInstance など World に絆付けされた何かから void UMyGameInstance::Something() { auto a = UA::GetInstance(); a.Rename( nullptr, this ); }
こうすると、以降は UA
のオブジェクト内部やそこからさらに NewObject<T>( this )
で生成したオブジェクトは Outer
の絆により GetWorld()
も期待動作するようになる。もちろん、もっと簡単な用途で単純に Outer
を変更したい場合も UObject::Rename
で同様に Outer
を変更できる。
UObject::Rename
は関数名からはオブジェクトの名前を変更するだけに見えるが、シグニチャーを見れば第2引数に UObject * NewOuter
とある。実装では第1引数に NULL
がデフォルトで与えられているが省略して呼ぶ意味があるかはさておき、名前を変更する必要の無い場合には nullptr
を与えれば良い事を推量できる。(実際に第1引数は nullptr
でそのように動作させられる)
// Runtime/CoreUObject/Public/UObject/Object.h /** Rename this object to a unique name.*/ virtual bool Rename( const TCHAR* NewName=NULL, UObject* NewOuter=NULL, ERenameFlags Flags=REN_None );
例によって事実上アンドキュメントなので使う場合はソースを読んだ方が良い。
// Runtime/CoreUObject/Private/UObject/Obj.cpp bool UObject::Rename( const TCHAR* InName, UObject* NewOuter, ERenameFlags Flags )
ERenameFlags
は RF_ClassDefaultObject
, REN_ForceGlobalUnique
, REN_Test
, REN_ForceNoResetLoaders
, REN_NonTransactional
, REN_DoNotDirty
, RF_Public
など指定すると意味があるようだが、さしあたり Outer
を設定、あるいは挿げ替えたいだけの場合には実引数は省略して REN_None
を与えれば良い。実装詳細的には LowLevelRename
と PostRename
も呼んでいるので思いのほか複雑な事をしている。