0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Unreal Engine]TArrayの参照をつくるときの注意点

Posted at

結論

TArrayの要素が更新された場合、TArrayのアドレスの再配置が行われるが参照で持っているアドレスは更新されない。

不正アクセスした際の挙動がわかりにくくなるため、スマートポインタで持っておくとよい。

どういうことか

UYourActor.h

USTRUCT()
struct FMyStruct
{
    GENERATED_BODY()
    FString MemberStr = TEXT("Member");
};


UCLASS()
class MYPROJECT_API UMyObject : public UObject
{
    GENERATED_BODY()

private:
    TArray<FMyStruct> MyStructs;

public:
    void RemoveLastElement()
    {
        MyStructs.Remove(MyStructs.Last());
    }
};

こういうクラスがあるとする。

FMyStruct& LastElementRef = MyStructs.Last();
RemoveLast();

// TArrayを変更したので要素のアドレスが変わった状態で参照にアクセス(不正アクセス)
UE_LOG(Log,Log, TEXT("%s"), *LastElementRef.MemberStr);

上記のように直接参照を受け取ると不正アクセスした時の壊れ方がややこしくなる。

TArrayの要素に変更があった場合でもアドレスが更新されず、参照が残る。

エディタではうまく動いていたがパッケージで突然変な動作になったり、エディタ実行でブレークポイントを使ってステップ実行すると正常動作するがブレークポイントを使わないと正常動作しない、といった事が起こる。

正常に動いているように見える場合もFMyStructを継承した構造体のデータにだけアクセスできなかったりする。

// 参照に対するポインタを指すポインタを作成する
TSharedPtr<FMyStruct*> LastElementPtr = MakeShared<FMyStruct*>(&MySructs.Last());
// 参照に対するポインタを指すポインタの実体 = 参照を取得
FMyStruct& LastElementRef = **LastElementPtr.Get();
RemoveLast();
// TArrayを変更したので要素のアドレスが変わった状態で参照にアクセス(不正アクセス)
UE_LOG(Log,Log, TEXT("%s"), *LastElementRef.MemberStr);

上記のようにスマートポインタを経由するとアドレスの更新が反映される。
比較的わかりやすく壊れてくれることが多い。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?