UE4 C++: TArray コンテナー

目次

概要

作成

要素を追加

Init: 複数の同一の値を入力します

追加: 重複した要素を追加でき、追加時に一時変数が作成およびコピーされます。

AddUnique: 重複した要素は追加できません

Emplace: 追加時に一時変数が作成されず、パフォーマンスは Add よりも優れています。

追加: 他の TArray 内の複数の要素、または通常の C 配列へのポインターと配列のサイズを一度に追加できます。

挿入: 単一の要素、または要素の配列のコピーを指定されたインデックスに追加します。

SetNum: 関数は配列要素の数を直接設定できます。

反復

範囲ベースの for ステートメント

定期的に

イテレータ

分類する

選別

HeapSort: ヒープソート (不安定)

StableSort: ソート後、同等の要素の相対的な順序が保証されます。StableSort はマージソートとして実装されています

お問い合わせ

GetData: この関数は配列内の要素へのポインタを返し、配列メモリに直接アクセスします。

GetTypeSize: 単一要素のサイズを取得します。

[]: インデックス演算子は要素を取得し、要素の操作に使用できる参照を返します。

IsValidIndex: コンテナに特定のインデックスが有効かどうかを尋ねます (0≤index())<>

最後: 配列の末尾からの逆インデックス。デフォルトは 0 です。

上: 最後の要素を返します。インデックスは受け入れません。

含む: 特定の要素を含むかどうか

ContainsByPredicate: 特定の述語に一致する要素を含むかどうか

Find: 要素が存在するかどうかを調べ、最初に見つかった要素のインデックスを返します。

FindLast: 要素が存在するかどうかを示し、最後に見つかった要素のインデックスを返します。

IndexOfByKey: 最初に一致した要素のインデックスを返します。見つからない場合は INDEX_NONE を返します。

IndexOfByPredicate: 特定の述語に一致する最初の要素のインデックスを検索します。

FindByKey: 要素を任意のオブジェクトと比較し、最初に一致した要素へのポインタを返すか、一致が見つからない場合は nullptr を返します。

FindByPredicate: IndexOfByPredicate と似ていますが、戻り値がインデックスではなくポインターである点が異なります。

FilterByPredicate: 特定の述語に一致する要素の配列を取得します。

要素を削除する

削除: 配列から要素を削除します。

RemoveSingle: 配列内の最初に一致した要素を削除します。

RemoveAt: インデックスによって要素を削除します

RemoveAll: 述語に一致する要素を削除します。

RemovSwap、RemoveAtSwap、RemoveAllSwap

空: 配列内のすべての要素を削除します。

リセット: 空と同様に、この関数はメモリを解放しません。

オペレーター

+=: 配列接続の Append 関数を置き換えることができます

MoveTemp: ある配列の内容を別の配列に移動でき、ソース配列は空になります。

==、!=: 配列を比較できます

ヒープ

Heapify: 既存の配列をヒープに変換します。

HeapPush: 新しい要素がヒープに追加され、他のノードがヒープを維持するために並べ替えられます。

HeapPop、HeadPopDiscard: ヒープの最上位ノードを削除します。

HeapRemoveAt: 配列内の指定されたインデックスにある要素を削除し、ヒープを維持するために要素を再配置します。

HeapTop: 配列を変更せずにヒープの最上位ノードを表示します

スラック

GetSlack: 配列内の Slack の量を調べます (Max()-Min() に相当) 

Max: コンテナーが再割り当てされる前に配列が保持できる要素の最大数を取得します。

空()

Reset(): Empty 関数と似ていますが、現在のメモリ割り当てによって要求された Slack が提供されている場合、この関数はメモリを解放しない点が異なります。ただし、要求された Slack が大きい場合は、より多くのメモリが割り当てられます。

Shrink(): すべての Slack を削除します

生の記憶


概要

  • TArray は、UE で最も一般的に使用されるコンテナ クラスです。高速、低メモリ消費、高セキュリティ
  • 拡張問題を考慮した設計ではないため、実際の運用では new や delete による TArray インスタンスの作成や破棄は行わないことを推奨します。
  • TArray 要素が数値型の場合、破棄されるときにその要素も破棄されます。TArray 変数が別の TArray で作成された場合、その要素は新しい変数にコピーされ、状態は共有されません

作成

TArray<int32> IntArray;

要素を追加

Init: 複数の同一の値を入力します

IntArray.Init(10, 5); //==>[10,10,10,10,10]

追加: 重複した要素を追加でき、追加時に一時変数が作成およびコピーされます。

AddUnique: 重複した要素は追加できません

Emplace: 追加時に一時変数が作成されず、パフォーマンスは Add よりも優れています。

TArray<FString> StrArr;
StrArr.Add(TEXT("Hello"));
IntArray.AddUnique(TEXT("Hello"));
StrArr.Emplace(TEXT("World")); //==>["Hello","World"]

追加: 他の TArray 内の複数の要素、または通常の C 配列へのポインターと配列のサイズを一度に追加できます。

FString Arr[] = { TEXT("of"), TEXT("Tomorrow") };
StrArr.Append(Arr, ARRAY_COUNT(Arr)); //==>["Hello","World","of","Tomorrow"]

新しい要素が配列に追加されると、配列のアロケーターは必要に応じてメモリを割り当てます。現在の配列サイズを超えると、デフォルトのアロケーターは複数の新しい要素を格納するのに十分なメモリを追加します。 関数Add と ほとんど同じ効果がありますが、若干の違いがあります。Emplace

  • Add(または Push) 要素タイプのインスタンスを配列にコピー (または移動) します。

  • Emplace 指定されたパラメータを使用して要素タイプの新しいインスタンスを構築します。

したがって 、 ではTArray<FString> 、Add 文字列リテラルを使用して一時的なものが作成され FString、 FString その一時的な内容がコンテナ内の new に移動されます FString が、 Emplace 新しいものは文字列リテラルを使用して直接作成されます FString最終結果は同じですが、 Emplace 一時ファイルの作成が回避されます。のような明白でない数値型の場合 FString 、一時ファイルは役に立つというよりも有害であることがよくあります。

全体として、Emplace よりも優れている Addため、呼び出しサイトで不要な一時変数を作成したり、そのような変数をコンテナにコピーまたは移動したりする必要がなくなります。経験則として、 Add 浅いタイプには使用し、 Emplace それ以外のタイプには使用します。Emplace は常に より効率的です Addが、 Add より読みやすい場合があります。

新しい要素は、同等の要素がまだ存在しない場合にのみコンテナに追加されますAddUnique 。次の要素型演算子を使用して等しいかどうかを確認します运算符==

StrArr.AddUnique(TEXT("!"));
// StrArr == ["Hello","World","of","Tomorrow","!"]

StrArr.AddUnique(TEXT("!"));
// StrArr is unchanged as "!" is already an element

挿入: 単一の要素、または要素の配列のコピーを指定されたインデックスに追加します。

StrArr.Insert(TEXT("Brave"), 1); //==>["Hello","Brave","World","of","Tomorrow","!"]

SetNum: 関数は配列要素の数を直接設定できます。

  • 新しい数値が現在の数値より大きい場合は、要素タイプのデフォルトのコンストラクターを使用して新しい要素を作成します
  • 新しい数値が現在の数値より小さい場合、SetNum は要素を削除します。
StrArr.SetNum(8); //==>["Hello","Brave","World","of","Tomorrow","!","",""]

StrArr.SetNum(6); //==>["Hello","Brave","World","of","Tomorrow","!"]

反復

範囲ベースの for ステートメント

FString JoinedStr;
for (auto& Str :StrArr)
{
	JoinedStr += Str;
	JoinedStr += TEXT(" ");
} // JoinedStr == "Hello Brave World of Tomorrow !"

定期的に

for (int32 Index = 0; Index != StrArr.Num(); ++Index)
{
	JoinedStr += StrArr[Index];
	JoinedStr += TEXT(" ");
}

イテレータ

CreateIterator 関数と CreateConstIterator 関数は、それぞれ要素への読み取り/書き込みアクセスと読み取り専用アクセスに使用できます。

for (auto It = StrArr.CreateConstIterator(); It; ++It)
{
	JoinedStr += *It;
	JoinedStr += TEXT(" ");
}

 

分類する

選別

StrArr.Sort(); //==>["!","Brave","Hello","of","Tomorrow","World"]

バイナリ述語はさまざまな照合順序 (ラムダ) を提供します

StrArr.Sort([](const FString& A, const FString& B){
		return A.len() < B.len();
	}); //按字符串长度排序, ==>["!","of","Hello","Brave","World","Tomorrow"]

HeapSort: ヒープソート (不安定)

バイナリ述語の有無にかかわらず、ペアの並べ替えを実行するために使用できます。これを使用するかどうかは、特定のデータと、並べ替え機能と比較した並べ替え効率によって決まります。ソートと同様に、ヒープソートも安定していません

StrArr.HeapSort([](const FString& A, const FString& B) {
	return A.Len() < B.Len();
}); //==>["!","of","Hello","Brave","World","Tomorrow"]

StableSort: ソート後、同等の要素の相対的な順序が保証されます。StableSort はマージソートとして実装されています

StrArr.StableSort([](const FString& A, const FString& B) {
	return A.Len() < B.Len();
}); //==>["!","of","Brave","Hello","World","Tomorrow"]

お問い合わせ

Num: 要素の数をクエリします。

int32 Count = StrArr.Num();  // Count == 6

GetData: この関数は配列内の要素へのポインタを返し、配列メモリに直接アクセスします。

このポインタは、配列が存在し、配列を変更する操作が実行されていない限り有効です。StrPtr の最初の Num インデックスのみを逆参照できます。

FString* StrPtr = StrArr.GetData();
// StrPtr[0] == "!"
// StrPtr[1] == "of"
// ...
// StrPtr[5] == "Tomorrow"
// StrPtr[6] - undefined behavior

GetTypeSize: 単一要素のサイズを取得します。

uint32 ElementSize = StrArr.GetTypeSize(); // ElementSize == sizeof(FString)

[]: インデックス演算子は要素を取得し、要素の操作に使用できる参照を返します。

FString Elem1 = StrArr[1]; // Elem1 == "of"

StrArr[3] = StrArr[3].ToUpper(); //==>["!","of","Brave","HELLO","World","Tomorrow"]

IsValidIndex: コンテナに特定のインデックスが有効かどうかを尋ねます (0≤index<Num())

bool bValidM1 = StrArr.IsValidIndex(-1);// bValidM1 == false
bool bValid0  = StrArr.IsValidIndex(0); // bValid0  == true
bool bValid5  = StrArr.IsValidIndex(5); // bValid5  == true
bool bValid6  = StrArr.IsValidIndex(6); // bValid6  == false

最後: 配列の末尾からの逆インデックス。デフォルトは 0 です。

上: 最後の要素を返します。インデックスは受け入れません。

FString ElemEnd  = StrArr.Last();  // ElemEnd  == "Tomorrow"
FString ElemEnd0 = StrArr.Last(0); // ElemEnd0 == "Tomorrow"
FString ElemEnd1 = StrArr.Last(1); // ElemEnd1 == "World"
FString ElemTop  = StrArr.Top();   // ElemTop  == "Tomorrow"

含む: 特定の要素を含むかどうか

bool bHello   = StrArr.Contains(TEXT("Hello"));   // bHello   == true
bool bGoodbye = StrArr.Contains(TEXT("Goodbye")); // bGoodbye == false

ContainsByPredicate: 特定の述語に一致する要素を含むかどうか

bool bLen5 = StrArr.ContainsByPredicate([](const FString& Str){
	return Str.Len() == 5;
}); // bLen5 == true

bool bLen6 = StrArr.ContainsByPredicate([](const FString& Str){
	return Str.Len() == 6;
}); // bLen6 == false

Find: 要素が存在するかどうかを調べ、最初に見つかった要素のインデックスを返します。

int32 Index;
if (StrArr.Find(TEXT("Hello"), Index)){  
	// Index == 3
}  

int32 Index2 = StrArr.Find(TEXT("Hello"));    // Index2 == 3
int32 IndexNone  = StrArr.Find(TEXT("None")); // IndexNone == INDEX_NONE(实质上是-1)

FindLast: 要素が存在するかどうかを示し、最後に見つかった要素のインデックスを返します。

int32 IndexLast;
if (StrArr.FindLast(TEXT("Hello"), IndexLast)){
	// IndexLast == 3, because there aren't any duplicates
}

int32 IndexLast2 = StrArr.FindLast(TEXT("Hello")); // IndexLast2 == 3

IndexOfByKey: 最初に一致した要素のインデックスを返します。見つからない場合は INDEX_NONE を返します。

IndexOfByPredicate: 特定の述語に一致する最初の要素のインデックスを検索します。

int32 Index = StrArr.IndexOfByPredicate([](const FString& Str){
	return Str.Contains(TEXT("r"));
}); // Index == 2

FindByKey: 要素を任意のオブジェクトと比較し、最初に一致した要素へのポインタを返すか、一致が見つからない場合は nullptr を返します。

auto* OfPtr  = StrArr.FindByKey(TEXT("of"))); // OfPtr  == &StrArr[1]
auto* ThePtr = StrArr.FindByKey(TEXT("the"))); // ThePtr == nullptr

FindByPredicate: IndexOfByPredicate と似ていますが、戻り値がインデックスではなくポインターである点が異なります。

auto* Len5Ptr = StrArr.FindByPredicate([](const FString& Str){
	return Str.Len() == 5;
}); // Len5Ptr == &StrArr[2]

auto* Len6Ptr = StrArr.FindByPredicate([](const FString& Str){
	return Str.Len() == 6;
}); // Len6Ptr == nullptr

FilterByPredicate: 特定の述語に一致する要素の配列を取得します。

auto Filter = StrArray.FilterByPredicate([](const FString& Str){
	return !Str.IsEmpty() && Str[0] < TEXT('M');
});

要素を削除する

削除: 配列から要素を削除します。

TArray<int32> ValArr;
int32 Temp[] = { 10, 20, 30, 5, 10, 15, 20, 25, 30 };
ValArr.Append(Temp, ARRAY_COUNT(Temp)); //==>[10,20,30,5,10,15,20,25,30]

ValArr.Remove(20); //==>[10,30,5,10,15,25,30]

RemoveSingle: 配列内の最初に一致した要素を削除します。

ValArr.RemoveSingle(30); //==>[10,5,10,15,25,30]

RemoveAt: インデックスによって要素を削除します

ValArr.RemoveAt(2); // 移除下标为2的元素, ==>[10,5,15,25,30]
ValArr.RemoveAt(99); // 引发错误,越界

RemoveAll: 述語に一致する要素を削除します。

ValArr.RemoveAll([](int32 Val) {
	return Val % 3 == 0; }); //移除为3倍数的所有数值, ==> [10,5,25]

RemovSwap、RemoveAtSwap、RemoveAllSwap

移動プロセスにはオーバーヘッドが発生します。残りの要素の順序付けが必要ない場合は、RemoveSwap、RemoveAtSwap、および RemoveAllSwap 関数を使用してこのオーバーヘッドを軽減できます。このような関数は、残りの要素の順序を保証しないため、タスクをより迅速に完了することを除いて、非可換バリアントと同様に機能します。

TArray<int32> ValArr2;
for (int32 i = 0; i != 10; ++i)
	ValArr2.Add(i % 5); //==>[0,1,2,3,4,0,1,2,3,4]

ValArr2.RemoveSwap(2); //==>[0,1,4,3,4,0,1,3]

ValArr2.RemoveAtSwap(1); //==>[0,3,4,3,4,0,1]

ValArr2.RemoveAllSwap([](int32 Val) {
	return Val % 3 == 0; }); //==>[1,4,4]

空: 配列内のすべての要素を削除します。

ValArr2.Empty(); //==>[]

リセット: 空と同様に、この関数はメモリを解放しません。

ValArr2.Reset (); //==>[]

オペレーター

配列は、標準のコピー コンストラクターまたは代入演算子を使用してコピーできる通常の数値型です。配列はその要素を厳密に所有するため、配列をコピーする操作は複雑であるため、新しい配列には要素の独自のコピーが含まれます。

TArray<int32> ValArr3;
ValArr3.Add(1);
ValArr3.Add(2);
ValArr3.Add(3);

auto ValArr4 = ValArr3; // ValArr4 == [1,2,3];
ValArr4[0] = 5;         // ValArr4 == [5,2,3]; ValArr3 == [1,2,3];

+=: 配列接続の Append 関数を置き換えることができます

ValArr4 += ValArr3; //==>[5,2,3,1,2,3]

MoveTemp: ある配列の内容を別の配列に移動でき、ソース配列は空になります。

ValArr3 = MoveTemp(ValArr4);  // ValArr3 == [5,2,3,1,2,3]; ValArr4 == []

==、!=: 配列を比較できます

要素の順序は重要です。2 つの配列は、要素の順序と数が同じ場合にのみ同一とみなされます。

TArray<FString> FlavorArr1;
FlavorArr1.Emplace(TEXT("Chocolate"));
FlavorArr1.Emplace(TEXT("Vanilla")); // FlavorArr1 == ["Chocolate","Vanilla"]

auto FlavorArr2 = FlavorArr1;        // FlavorArr2 == ["Chocolate","Vanilla"]

bool bComparison1 = FlavorArr1 == FlavorArr2;  // bComparison1 == true

for ( auto& Str : FlavorArr2 )
{
	Str = Str.ToUpper();
} // FlavorArr2 == ["CHOCOLATE","VANILLA"]

bool bComparison2 = FlavorArr1 == FlavorArr2; // bComparison2 == true,因为FString的对比忽略大小写

Exchange(FlavorArr2[0], FlavorArr2[1]); // FlavorArr2 == ["VANILLA","CHOCOLATE"]

bool bComparison3 = FlavorArr1 == FlavorArr2; // bComparison3 == false,因为两个数组内的元素顺序不同

ヒープ

TArray には、バイナリ ヒープ データ構造をサポートする機能があります。ヒープは、親ノードがその子ノードと同じかそれ以上に順序付けされているバイナリ ツリーの一種です。配列として実装される場合、ツリーのルートは要素 0 にあり、インデックス N にあるノードの左側と右側の子は、それぞれインデックス 2N+1 と 2N+2 を持ちます。子ノードの相互に特定の順序はありません。

Heapify: 既存の配列をヒープに変換します。

TArray<int32> HeapArr;
for (int32 Val = 10; Val != 0; --Val){
	HeapArr.Add(Val);
} // HeapArr == [10,9,8,7,6,5,4,3,2,1]

HeapArr.Heapify(); // HeapArr == [1,2,4,3,6,5,8,10,7,9]

HeapPush: 新しい要素がヒープに追加され、他のノードがヒープを維持するために並べ替えられます。

HeapArr.HeapPush(4); // HeapArr == [1,2,4,3,4,5,8,10,7,9,6]

HeapPop、HeadPopDiscard: ヒープの最上位ノードを削除します。

これら 2 つの関数の違いは、前者は要素の型を参照して最上位要素のコピーを返すのに対し、後者は何も返さずに単に最上位ノードを削除することです。2 つの関数によって取得される配列の変更には一貫性があり、他の要素を正しく並べ替えることでヒープを維持できます。

int32 TopNode;
HeapArr.HeapPop(TopNode); // TopNode == 1; HeapArr == [2,3,4,6,4,5,8,10,7,9]

HeapRemoveAt: 配列内の指定されたインデックスにある要素を削除し、ヒープを維持するために要素を再配置します。

HeapArr.HeapRemoveAt(1); // HeapArr == [2,4,4,6,9,5,8,10,7]

HeapTop: 配列を変更せずにヒープの最上位ノードを表示します

int32 Top = HeapArr.HeapTop();  // Top == 2

スラック

配列のサイズは変更できるため、使用するメモリの量は変化します。要素が追加されるたびに再割り当てを行う必要を避けるために、アロケーターは通常、必要以上のメモリを提供し、後続の Add 呼び出しで再割り当てによるパフォーマンスの低下が発生しないようにします。また、通常、要素を削除してもメモリは解放されません。

  • コンテナ内の既存の要素の数と、次の割り当てまでに追加できる要素の数の差は Slack です
  • デフォルトで構築される配列はメモリを割り当てず、スラックは初期状態では 0 です。

GetSlack: 配列内の Slack の量を調べます (Max()-Min() に相当) 

Max: コンテナーが再割り当てされる前に配列が保持できる要素の最大数を取得します。

  • アロケータは再割り当て後のコンテナ内の Slack の量を決定するため、Slack は一定ではありません
TArray<int32> SlackArray;
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 0
// SlackArray.Max()      == 0

SlackArray.Add(1);
// SlackArray.GetSlack() == 3
// SlackArray.Num()      == 1
// SlackArray.Max()      == 4

SlackArray.Add(2);
SlackArray.Add(3);
SlackArray.Add(4);
SlackArray.Add(5);
// SlackArray.GetSlack() == 17
// SlackArray.Num()      == 5
// SlackArray.Max()      == 22
  • Slack を管理する必要はありませんが、ニーズに合わせて配列を最適化するために Slack を管理できます。

空()

たとえば、約 100 個の新しい要素を配列に追加する必要がある場合、追加する前に少なくとも 100 個の新しい要素を保存できる Slack があることを確認すると、要素を追加するときにメモリを割り当てる必要がなくなります。上記の 関数はEmpty オプションの Slack パラメータを受け入れます

SlackArray.Empty();
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 0
// SlackArray.Max()      == 0
SlackArray.Empty(3);
// SlackArray.GetSlack() == 3
// SlackArray.Num()      == 0
// SlackArray.Max()      == 3
SlackArray.Add(1);
SlackArray.Add(2);
SlackArray.Add(3);
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 3
// SlackArray.Max()      == 3

Reset(): Empty 関数と似ていますが、現在のメモリ割り当てによって要求された Slack が提供されている場合、この関数はメモリを解放しない点が異なります。ただし、要求された Slack が大きい場合は、より多くのメモリが割り当てられます。

SlackArray.Reset(0);
// SlackArray.GetSlack() == 3
// SlackArray.Num()      == 0
// SlackArray.Max()      == 3
SlackArray.Reset(10);
// SlackArray.GetSlack() == 10
// SlackArray.Num()      == 0
// SlackArray.Max()      == 10

Shrink(): すべての Slack を削除します

この関数は割り当てを希望のサイズに変更し、実際に要素を移動せずに現在の要素シーケンスを保持できるようにします。

SlackArray.Add(5);
SlackArray.Add(10);
SlackArray.Add(15);
SlackArray.Add(20);
// SlackArray.GetSlack() == 6
// SlackArray.Num()      == 4
// SlackArray.Max()      == 10
SlackArray.Shrink();
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 4
// SlackArray.Max()      == 4

生の記憶

参考リンク:

 【UE4 C++の基礎】<5>コンテナ—TArray

Unreal Engine の配列コンテナ | Unreal Engine 5.0 ドキュメント

おすすめ

転載: blog.csdn.net/Jason6620/article/details/126504319