[UE C++] TMap

[UE C++] TMap

Nach TArrayist der am häufigsten verwendete Container in Unreal Engine 4 (UE4) TMap. TMapÄhnlich wie bei TSetbasiert ihre Struktur auf dem Hashing der Schlüssel. Aber im Gegensatz zu TSetspeichert dieser Container Daten als Schlüssel-Wert-Paare (TPair<KeyType, ValueType>) und verwendet Schlüssel nur zum Speichern und Abrufen.

Es gibt zwei Arten von Karten: TMapund TMultiMap. Der Unterschied zwischen den beiden besteht darin, dass TMapder Schlüssel eindeutig ist , während TMultiMapmehrere identische Schlüssel darin gespeichert werden können. Wenn beim Hinzufügen eines neuen Schlüsselwerts in TMapder verwendete Schlüssel mit dem ursprünglichen Schlüssel-Wert-Paar übereinstimmt, ersetzt das neue Schlüssel-Wert-Paar das ursprüngliche Schlüssel-Wert-Paar. In TMultiMapkann der Container sowohl neue Schlüssel-Wert-Paare als auch ursprüngliche Schlüssel-Wert-Paare speichern.

  • Der Elementtyp ist ein Schlüssel-Wert-Paar (TPair<KeyType, ValueType>), es ist jedoch selten erforderlich, direkt auf TPairden Typ zu verweisen
  • Homogener Container , alle Elemente sollten genau vom gleichen Typ sein
  • Ein Werttyp , der die üblichen Kopier-, Zuweisungs- und Destruktorvorgänge sowie einen starken Besitz seiner Elemente unterstützt. Wenn TMapes zerstört wird, werden seine Elemente zerstört. Schlüssel und Werte müssen ebenfalls Werttypen sein
  • Hash-Container , was bedeutet, dass der Schlüsseltyp GetTypeHashFunktionen unterstützen und Operatoren bereitstellen muss ==, um zu vergleichen, ob jeder Schlüssel gleich ist.
  • Allokatoren werden unterstützt , um das Speicherzuteilungsverhalten zu steuern, aber im Gegensatz zu TArray, handelt es sich dabei eher um Sammlungszuordnungen als um standardmäßige UE4-Zuordnungen wie FHeapAllocatorund . TInlineAllocatorDer Sammlungszuordner ( TSetAllocatorKlasse) definiert die Anzahl der Hash-Buckets, die die Karte verwenden soll, und welcher standardmäßige UE4-Zuordner zum Speichern der Hashes und Elemente verwendet werden soll.
  • KeyFuncs ist der letzte TMapVorlagenparameter, der der Map mitteilt, wie sie den Schlüssel vom Elementtyp erhält, wie sie zwei Schlüssel auf Gleichheit vergleicht und wie sie den Schlüssel hasht. Diese Parameter haben Standardwerte, sie geben einfach einen Verweis auf den Schlüssel zurück, verwenden Operatoren, ==um die Gleichheit zu bestimmen, und rufen Nicht-Member- GetTypeHashFunktionen für Hash-Berechnungen auf. Wenn Ihr Schlüsseltyp diese Funktionen unterstützt, können Sie ihn als Kartenschlüssel verwenden, ohne benutzerdefinierte KeyFuncs bereitzustellen
  • Im Gegensatz dazu ist die relative Reihenfolge der Elemente TArrayim Speicher weder zuverlässig noch stabil , und die Iteration über diese Elemente führt wahrscheinlich dazu, dass sie in einer anderen Reihenfolge zurückgegeben werden als der Reihenfolge, in der sie hinzugefügt wurden.TMap
  • TMapEs ist unwahrscheinlich, dass die Elemente im Speicher zusammenhängend angeordnet werden, und die TMapeinzige unterstützte Datenstruktur ist ein spärliches Array , das Lücken zwischen Elementen effektiv unterstützen kann. Wenn Elemente aus der Karte entfernt werden, entstehen Lücken in dünn besetzten Arrays. Durch das Hinzufügen neuer Elemente zum Array werden diese Lücken geschlossen. Auch wenn TMapElemente nicht gemischt werden, um Lücken zu füllen, können Zeiger auf zugeordnete Elemente dennoch ungültig werden, da der gesamte Speicher möglicherweise neu zugewiesen wird, wenn der Speicher voll ist und neue Elemente hinzugefügt werden.

1. Erstellung und Initialisierung

// 默认构造
TMap<int32, FString> TestMap;

// 拷贝构造
TMap<int32, FString> TempMap{ TestMap };

// 移动拷贝构造
TMap<int32, FString> TempMap{ MoveTemp(TestMap) };

// 初始化列表
TMap<int32, FString> TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };

// TTuple/TPair 初始化列表
TMap<int32, FString> TestMap = { TTuple<int32,FString> { 1,TEXT("PairOne") }, TPair<int32,FString>{2,TEXT("Two")} ,{3,TEXT("Three")} };

2. erhöhen

2.1 Hinzufügen

Fügen Sie ein Element hinzu TMap, es gibt 8 Überladungen, unterstützt die Bewegungssemantik und kann in drei Kategorien unterteilt werden. Der Rückgabewert ist ein Verweis auf den Wert in der TMap. Es ist jedoch wichtig zu beachten, dass dieser Verweis nur bis zur nächsten Änderung eines Schlüssels in der TMap gültig ist (neue Elemente werden hinzugefügt, der gesamte Speicher wird möglicherweise neu zugewiesen).

// 输入Key 和 Value
ValueType& Add(const KeyType&  InKey, const ValueType&  InValue);
// 仅输入Key,Value会调用默认构造函数,FString的为""
ValueType& Add(const KeyType&  InKey);
// 输入TTuple
ValueType& Add(const TTuple<KeyType, ValueType>&  InKeyValue);
TestMap.Add(1, TEXT("One"));

TestMap.Add(2);

TestMap.Add(MakeTuple<int32, FString>(3, TEXT("Three")));

// TestMap == [
//  { Key:1, Value:"One"    },
//  { Key:2, Value:""       },
//  { Key:3, Value:"Three"  }
// ]

Die Elemente sind hier in der Einfügereihenfolge angeordnet, es gibt jedoch keine Garantie dafür, dass die Elemente diese Reihenfolge tatsächlich im Speicher beibehalten. Wenn es sich um eine neue Zuordnung handelt, bleibt die Einfügereihenfolge möglicherweise erhalten. Je mehr Einfügungen und Löschungen es jedoch gibt, desto größer ist die Wahrscheinlichkeit, dass das neue Element am Ende nicht angezeigt wird.

Dies ist nicht der Fall TMultiMap, daher muss jeder Schlüssel eindeutig sein. Wenn Sie versuchen, einen doppelten Schlüssel hinzuzufügen, passiert Folgendes:

TestMap.Add(2, TEXT("Two"));

// TestMap == [
//  { Key:1, Value:"One"    },
//  { Key:2, Value:"Two"    },
//  { Key:3, Value:"Three"  }
// ]

Die Karte enthält immer noch 3 Elemente, aber das vorherige „“ mit einem Schlüsselwert von 2 wurde durch „Zwei“ ersetzt.

2.2 Standort

Wie TArraybei können Sie Emplacestattdessen auch verwenden, Addum zu verhindern, TMapdass beim Einfügen temporäre Dateien erstellt werden. TArrayIm Gegensatz zu können Elemente jedoch nur über den Einzelparameter-Konstruktor in TMap eingefügt werden . Der Rückgabewert ist Addderselbe wie

// 输入单参数构造Key,Value默认构造
template <typename InitKeyType>
ValueType& Emplace(InitKeyType&& InKey);
// 输入两个参数分别构造Key,与Value
template <typename InitKeyType, typename InitValueType>
ValueType& Emplace(InitKeyType&& InKey, InitValueType&& InValue);
TestMap.Emplace(1);
TestMap.Emplace(2, TEXT("Two"));

// TestMap == [
//  { Key:1, Value:""    },
//  { Key:2, Value:"Two" },
// ]

Hier werden die Schlüssel und Werte direkt an ihre jeweiligen Konstruktoren übergeben. Dies hat eigentlich keine Auswirkungen auf den int32-Schlüssel, vermeidet jedoch die Erstellung eines temporären FStrings für den Wert

2.3 Anhang

Fügt der TMap ein weiteres TMap-Element hinzu und unterstützt die Bewegungssemantik.

TestMap.Emplace(1);
TestMap.Emplace(2, TEXT("Two"));
TMap<int32, FString> TempMap{ {1,TEXT("One")},{3,TEXT("Three")} };
TestMap.Append(TempMap);

// TestMap == [
//  { Key:1, Value:"One"    },
//  { Key:2, Value:"Two"    },
//  { Key:3, Value:"Three"  }
// ]

3. Löschen

3.1 Entfernen

Löschen Sie das angegebene Schlüssel-Wert-Paar basierend auf dem Schlüsselwert. Der Rückgabewert ist die Anzahl der entfernten Elemente. Wenn die TMap keine Elemente enthält, die mit dem Schlüssel übereinstimmen, kann der Rückgabewert Null sein.

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };
TestMap.Remove(1);

// TestMap == [
//  { Key:2, Value:"Two"    },
//  { Key:3, Value:"Three"  }
// ]

3.2 FindAndRemoveChecked

Entfernt ein Element aus einer TMap und gibt seinen Wert zurück. Der „Checked“-Teil des Namens gibt an, dass TMap aufgerufen wird, wenn der Schlüssel nicht vorhanden ist check(entspricht in UE4 assert).

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };
TestMap.FindAndRemoveChecked(1);

// Assert!
TestMap.FindAndRemoveChecked(5);

3.3 RemoveAndCopyValue

Funktioniert Removeähnlich wie , außer dass der Wert des entfernten Elements in den Referenzparameter kopiert wird. Wenn der angegebene Schlüssel in der TMap nicht vorhanden ist, bleiben die Ausgabeparameter unverändert und die Funktion gibt „false“ zurück

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };
FString TempString;

// TempString == "One",Return == true
TestMap.RemoveAndCopyValue(1, TempString);
// TempString == "One" 没变化,Return == false
TestMap.RemoveAndCopyValue(5, TempString);

3.4 Leer

TMap löschen, der Eingabeparameter ist die Slack-Menge von TMap, Standard = 0

void Empty(int32 ExpectedNumElements = 0);

3.5 Zurücksetzen

Löscht die TMap, ändert jedoch nicht die Speicherzuordnung der TMap. Anders als bei TArray gibt es keine Eingabeparameter

void Reset();

4. Iteration

4,1 Reichweite

for (auto& Item : PrintMap)
{
    Item.Key;
    Item.Value;
}

4.2 Elementiterator

TMap.CreateIterator()Lesbare, beschreibbare und TMap.CreateConstIterator()schreibgeschützte Iteratoren

for (auto It = TestMap.CreateIterator(); It; ++It)
{
    // Key
    It->Key;
    It.Key();
    (*It).Key;

    // Value
    It->Value;
    It.Value();
    (*It).Value;
}

4.3 Schlüsseliterator

CreateKeyIterator()Lesbare, beschreibbare und CreateConstKeyIterator()schreibgeschützte Iteratoren

Erstellen Sie einen Iterator für den Wert, der dem angegebenen Schlüssel in der Karte zugeordnet ist. Er ist in TMap nutzlos, da ein Schlüssel nur einem Wert entspricht. Er wird für TMultiMap verwendet.

TMultiMap<int32, FString> TestMulMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} ,{1,TEXT("OneOne")} };

for (auto Item = TestMulMap.CreateKeyIterator(1); Item; ++Item)
{
    UE_LOG(LogTemp, Warning, TEXT("Key:%d\tValue:%s"), Item.Key(), *Item.Value());
}

// Key:1   Value:OneOne
// Key:1   Value:One

5. Überprüfen

5.1 Anz

Fragen Sie die Anzahl der gespeicherten Elemente ab

int32 Count = TestMap.Num();

5.2 Enthält

Bestimmen Sie anhand des eingegebenen Schlüsselwerts, ob ein Schlüssel-Wert-Paar vorhanden ist, und geben Sie einen booleschen Wert zurück.

bool Contains(KeyConstPointerType Key) const;

5.3 Finden

Bestimmen Sie anhand des eingegebenen Schlüsselwerts, ob ein Schlüssel-Wert-Paar vorhanden ist. Wenn es vorhanden ist, wird der Zeiger zurückgegeben, der dem Wert des Schlüssels entspricht. Andernfalls wird nullptr zurückgegeben.

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };
FString* TempString = TestMap.Find(1);

5.4 FindOrAdd

FindOrAddGibt einen Verweis auf den Wert zurück, der dem angegebenen Key zugeordnet ist . Wenn der Schlüssel nicht in der TMap vorhanden ist, FindOrAddwird ein neu erstelltes Element (unter Verwendung des angegebenen Schlüssels und des standardmäßig erstellten Werts) zurückgegeben und das Element wird der TMap hinzugefügt. FindOrAdd Änderbar TMap , funktioniert also nur mit nicht konstantem TMap .

ValueType& FindOrAdd(const KeyType&  Key);
// 可能会Add,所以存在移动语义
ValueType& FindOrAdd(      KeyType&& Key);
TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };

FString TempString = TestMap.FindOrAdd(1);
// TempString == "One"
// TestMap == [
//  { Key:1, Value:"One"    },
//  { Key:2, Value:"Two"    },
//  { Key:3, Value:"Three"  }
// ]
TempString = TestMap.FindOrAdd(4);
// TempString == ""
// TestMap == [
//  { Key:1, Value:"One"    },
//  { Key:2, Value:"Two"    },
//  { Key:3, Value:"Three"  },
//  { Key:4, Value:""       }
// ]

5.5 FindRef

FindRefGibt eine Kopie des mit dem angegebenen Schlüssel verknüpften Werts zurück. Wenn der angegebene Schlüssel nicht TMapin gefunden wird , wird der standardmäßig erstellte Wert zurückgegeben. FindRef Es werden keine neuen Elemente erstellt, daher kann es sowohl mit konstanten als auch mit nicht konstanten TMaps verwendet werden.

ValueType FindRef(KeyConstPointerType Key) const;
TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };

FString TempString = TestMap.FindRef(1);
// TempString == "One"
// TestMap == [
//  { Key:1, Value:"One"    },
//  { Key:2, Value:"Two"    },
//  { Key:3, Value:"Three"  }
// ]
TempString = TestMap.FindRef(4);
// TempString == ""
// TestMap == [
//  { Key:1, Value:"One"    },
//  { Key:2, Value:"Two"    },
//  { Key:3, Value:"Three"  }
// ]

Auch wenn TMapder Schlüssel nicht in gefunden wird FindOrAddund FindReferfolgreich ausgeführt wird, kann er sicher aufgerufen werden, ohne dass normale Sicherheitsprozeduren durchgeführt werden müssen (z. B. die vorherige Prüfung von „Contains“ oder die Validierung des Rückgabewerts).

5.6 FindKey

Führt eine umgekehrte Suche durch, was bedeutet, dass der bereitgestellte Wert mit einem Schlüssel übereinstimmt, und gibt einen Zeiger auf den ersten Schlüssel zurück , der mit dem bereitgestellten Wert übereinstimmt . Die Suche nach einem Wert, der in TMap nicht vorhanden ist, gibt nullptr zurück.

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };
// *TempInt == 1
const int32* TempInt = TestMap.FindKey(TEXT("One"));

Bitte beachten Sie, dass die Rückgabe der ersten nicht garantieren kann, dass die zuerst hinzugefügte zurückgegeben wird. Es wird nur die zuerst abgefragte zurückgegeben.

5.7 KeyArray generieren

Füllen Sie TArray mit Kopien aller Keys . Macht das TArray leer, sodass die Anzahl der erzeugten Elemente immer gleich der Anzahl der Elemente in der Map ist.

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };
TArray<int32> TempArray = TestMap.GenerateKeyArray(TempArray);
// TempArray == [1,2,3];

5.8 ValueArray generieren

Füllen Sie das TArray mit Kopien aller Values ​​. Macht das TArray leer, sodass die Anzahl der erzeugten Elemente immer gleich der Anzahl der Elemente in der Map ist.

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };
TArray<FString> TempArray = TestMap.GenerateKeyArray(TempArray);
// TempArray == ["One","Two","Three"];

5.9 GetKeys

Holen Sie sich die in dieser Karte enthaltenen eindeutigen Schlüssel. In TMap hat es GenerateKeyArrayden gleichen Effekt wie in , aber in TMultiMapwird das gefilterte TArray/TSet erhalten. Der Rückgabewert ist die Anzahl der eindeutigen Schlüssel (Num). Sie werden alle im Artikel beschrieben TMap, aber tatsächlich TMultiMapexistieren diese APIs auch und sie erben alle von TMapBase.

int32 GetKeys(TArray<KeyType, Allocator>& OutKeys) const;

int32 GetKeys(TSet<KeyType, Allocator>& OutKeys) const;

5.10 FilterByPredicate

Nach Prädikat filtern TMapund das gefilterte Ergebnis zurückgebenTMap

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };

TMap<int32, FString> TempMap = TestMap.FilterByPredicate([](TPair<int32, FString> Item) { return Item.Key <= 2; });

6. Sortieren

TMap kann sortiert werden. Nach dem Sortieren zeigt die iterative Karte die Elemente in sortierter Reihenfolge an, die Reihenfolge kann sich jedoch ändern, wenn die Karte das nächste Mal geändert wird.

6.1 Schlüsselsortierung

Schlüsselgeordnete, instabile, gleichwertige Elemente können in MultiMap in beliebiger Reihenfolge erscheinen. Der Eingabeparameter ist ein binäres Prädikat

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };
TestMap.KeySort([](int32 A, int32 B) { return A > B; });
// TestMap == [
//  { Key:3, Value:"Three"  },
//  { Key:2, Value:"Two"    },
//  { Key:1, Value:"One"    }
// ]


TMultiMap<int32, FString> TestMulMap = { {1,TEXT("One")}, {1,TEXT("OneOne")},{2,TEXT("Two")} ,{3,TEXT("Three")} };
TestMulMap.KeySort([](int32 A, int32 B) { return A > B; });
// TestMulMap == [
//  { Key:3, Value:"Three"  },
//  { Key:2, Value:"Two"    },
//  { Key:1, Value:"OneOne" },
//  { Key:1, Value:"One"    }
// ]

6.2 KeyStableSort

Schlüsselsortierung, stabil. Gleichwertige Elemente behalten ihre bestehende Reihenfolge in MultiMap bei

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };
TestMap.KeySort([](int32 A, int32 B) { return A > B; });
// TestMap == [
//  { Key:3, Value:"Three"  },
//  { Key:2, Value:"Two"    },
//  { Key:1, Value:"One"    }
// ]


TMultiMap<int32, FString> TestMulMap = { {1,TEXT("One")}, {1,TEXT("OneOne")},{2,TEXT("Two")} ,{3,TEXT("Three")} };
TestMulMap.KeySort([](int32 A, int32 B) { return A > B; });
// TestMulMap == [
//  { Key:3, Value:"Three"  },
//  { Key:2, Value:"Two"    },
//  { Key:1, Value:"One"    },
//  { Key:1, Value:"OneOne" }
// ]

6.3 ValueSort/ValueStableSort

Wertsortierung, instabil/stabil, Verwendung stimmt mit Schlüssel überein.

7. Betreiber

7,1 =

Der Zuweisungsoperator ähnelt dem Konstruktor, daher werde ich hier nicht auf Details eingehen.

7.2 []

Rufen Sie den Verweis auf den entsprechenden Wert über den Schlüssel ab und rufen Sie ihn intern auf FindChecked. Wenn der Schlüssel nicht vorhanden ist, wird Assert ausgelöst.

TestMap = { {1,TEXT("One")}, {2,TEXT("Two")} ,{3,TEXT("Three")} };
TestMap[1] = TEXT("OneOne");
// TestMap == [
//  { Key:1, Value:"OneOne"    },
//  { Key:2, Value:"Two"    },
//  { Key:3, Value:"Three"  }
// ]

8. Locker

Slack wird Speicher zugewiesen, der keine Elemente enthält. Durch den Aufruf Reservewird Speicher reserviert, ohne Elemente hinzuzufügen; durch Aufruf Resetoder Aufruf mit einem Slack-Argument ungleich Null Emptywerden Elemente entfernt, ohne den von ihnen verwendeten Speicher freizugeben. Slack optimiert den Prozess des Hinzufügens neuer Elemente zu einer Karte, da vorab zugewiesener Speicher verwendet werden kann, anstatt neuen Speicher zuweisen zu müssen. Dies ist auch beim Entfernen von Elementen nützlich, da das System keinen Speicher freigeben muss. Diese Methode ist besonders nützlich, wenn Sie eine Karte leeren, die Sie sofort wieder mit denselben oder weniger Elementen füllen möchten.

TMap überprüft nicht die Anzahl der vorab zugewiesenen Elemente wie die Max-Funktion in TArray.

8.1 Reserve

Speicher vorab zuweisen. Wenn die eingegebene Zahl größer als die Anzahl der Elemente ist, wird Slack generiert.

TestMap.Reserve(10);

8.2 Schrumpfen

Entfernt den gesamten Durchhang vom Ende des Containers, hinterlässt jedoch leere Elemente in der Mitte oder am Anfang. Wenn Sie den gesamten Spielraum entfernen möchten, müssen Sie ihn zuerst aufrufenCompact

TMap<int32,FString> FruitMap;

for (int32 i = 0; i < 10; i += 2)
{
    FruitMap.Remove(i);
}
// FruitMap == [
//  { Key:9, Value:"Fruit9" },
//  <invalid>,
//  { Key:7, Value:"Fruit7" },
//  <invalid>,
//  { Key:5, Value:"Fruit5" },
//  <invalid>,
//  { Key:3, Value:"Fruit3" },
//  <invalid>,
//  { Key:1, Value:"Fruit1" },
//  <invalid>
// ]
FruitMap.Shrink();
// FruitMap == [
//  { Key:9, Value:"Fruit9" },
//  <invalid>,
//  { Key:7, Value:"Fruit7" },
//  <invalid>,
//  { Key:5, Value:"Fruit5" },
//  <invalid>,
//  { Key:3, Value:"Fruit3" },
//  <invalid>,
//  { Key:1, Value:"Fruit1" }
// ]

Im obigen Code entfernt Shrink nur ein ungültiges Element, da am Ende nur ein leeres Element vorhanden ist.

8.3 Kompakt

Gruppieren Sie die leeren Elemente und platzieren Sie sie am Ende. Die Reihenfolge der Elemente in den folgenden Beispielen ist möglicherweise nicht korrekt und Compactdie Reihenfolge zwischen den Elementen kann sich ändern. Wenn Sie die Reihenfolge nicht ändern möchten, können Sie verwendenCompactStable

FruitMap.Compact();
// FruitMap == [
//  { Key:9, Value:"Fruit9" },
//  { Key:7, Value:"Fruit7" },
//  { Key:5, Value:"Fruit5" },
//  { Key:3, Value:"Fruit3" },
//  { Key:1, Value:"Fruit1" },
//  <invalid>,
//  <invalid>,
//  <invalid>,
//  <invalid>
// ]
FruitMap.Shrink();
// FruitMap == [
//  { Key:9, Value:"Fruit9" },
//  { Key:7, Value:"Fruit7" },
//  { Key:5, Value:"Fruit5" },
//  { Key:3, Value:"Fruit3" },
//  { Key:1, Value:"Fruit1" }
// ]

9. Tastenfunktionen

Solange der Typ über Operator- ==und Nicht-Member- GetTypeHashÜberladungen verfügt, kann er ohne Änderungen als Schlüsseltyp für eine TMap verwendet werden. Möglicherweise möchten Sie jedoch Typen als Schlüssel verwenden, ohne diese Funktionen zu überlasten. In diesen Fällen können KeyFuncs angepasst werden.

Um KeyFuncs für Schlüsseltypen zu erstellen, müssen zwei Typedefs und drei statische Funktionen wie folgt definiert werden:

  • KeyInitType——Der Typ, der zum Übergeben des Schlüssels verwendet wird.
  • ElementInitType– Der Typ, der zum Übergeben des Elements verwendet wird.
  • KeyInitType GetSetKey(ElementInitType Element)——Gibt den Schlüssel des Elements zurück.
  • bool Matches(KeyInitType A, KeyInitType B)– Gibt „true“ zurück, wenn A und B gleich sind, andernfalls „false“.
  • uint32 GetKeyHash(KeyInitType Key)——Gibt den Hash-Wert des Schlüssels zurück.

KeyInitTypeund ElementInitTypesind Typdefinitionen für die allgemeine Übergabekonvention für Schlüsseltypen und Werttypen. Sie sind normalerweise ein Wert eines oberflächlichen Typs und eine konstante Referenz eines nicht expliziten Typs. Denken Sie daran, dass der zugeordnete Elementtyp TPair ist.

Struktur als Schlüssel:

struct FMyStruct
{
    // String which identifies our key
    FString UniqueID;

    // Some state which doesn't affect struct identity
    float SomeFloat;

    explicit FMyStruct(float InFloat)
        :UniqueID (FGuid::NewGuid().ToString())
        , SomeFloat(InFloat)
    {
    }
};

Benutzerdefinierte KeyFuncs:

struct FMyStruct
{
    // String which identifies our key
    FString UniqueID;

    // Some state which doesn't affect struct identity
    float SomeFloat;

    explicit FMyStruct(float InFloat)
        :UniqueID (FGuid::NewGuid().ToString())
        , SomeFloat(InFloat)
    {
    }
};
template <typename ValueType>
struct TMyStructMapKeyFuncs :
    BaseKeyFuncs<
        TPair<FMyStruct, ValueType>,
        FString
    >
{
private:
    typedef BaseKeyFuncs<
        TPair<FMyStruct, ValueType>,
        FString
    > Super;

public:
    typedef typename Super::ElementInitType ElementInitType;
    typedef typename Super::KeyInitType     KeyInitType;

    static KeyInitType GetSetKey(ElementInitType Element)
    {
        return Element.Key.UniqueID;
    }

    static bool Matches(KeyInitType A, KeyInitType B)
    {
        return A.Compare(B, ESearchCase::CaseSensitive) == 0;
    }

    static uint32 GetKeyHash(KeyInitType Key)
    {
        return FCrc::StrCrc32(*Key);
    }
};

FMyStruct verfügt über eine eindeutige Kennung ( UniqueID) und einige andere Daten, die nichts mit der Identität zu tun haben ( SomeFloat). GetTypeHashDie Operatoren „and“ ==gelten hier nicht, da der Operator ==keine Daten jeglicher Art für allgemeine Zwecke ignorieren sollte, dies aber gleichzeitig tun muss ( UniqueIDandere Daten als diese ignorieren), um GetTypeHashmit dem Verhalten konsistent zu sein, das ( GetTypeHash) nur interessiert über UniqueIDFeld. Die folgenden Schritte helfen beim Erstellen benutzerdefinierter KeyFuncs für FMyStruct:

  1. Erstens die Vererbung BaseKeyFuncs, da sie dabei helfen kann, bestimmte Typen zu definieren, einschließlich KeyInitTypeund ElementInitType.
    BaseKeyFuncsVerwenden Sie zwei Vorlagenparameter: den zugeordneten Elementtyp und den Schlüsseltyp.
    • Wie bei allen Karten ist der Elementtyp TPair, wobei FMyStruct als KeyType und der Template-Parameter von TMyStructMapKeyFuncs als ValueType verwendet werden. Deklarieren Sie TMyStructMapKeyFuncs als Vorlagenklasse und verwenden Sie den Vorlagenparameter ValueType für TPair. Dadurch kann vermieden werden, dass jedes Mal neue KeyFuncs erstellt werden, wenn FMyStruct als Schlüssel von TMap verwendet wird.
    • Der zweite BaseKeyFuncs-Parameter ist vom Typ Key und darf nicht mit dem im Element gespeicherten Schlüssel (KeyType von TPair) verwechselt werden. Da diese Map UniqueID(von FMyStruct) als Schlüssel verwenden soll, wird hier FString verwendet.
  2. Definieren Sie dann die drei erforderlichen statischen KeyFuncs-Funktionen:
    • Der erste besteht darin GetSetKey, dass die Funktion den Schlüssel des angegebenen Elementtyps zurückgibt. Da der Elementtyp TPair und der Schlüssel ist UniqueID, kann die Funktion UniqueID direkt zurückgeben.
    • Die zweite statische Funktion ist Matches: Diese Funktion nimmt die Schlüssel zweier Elemente ( GetSetKeyerhalten durch) und vergleicht sie dann auf Gleichheit. In FStrings unterscheidet der Standardäquivalenztest (Operator ==) nicht zwischen Groß- und Kleinschreibung. Um ihn durch eine Suche unter Berücksichtigung der Groß- und Kleinschreibung zu ersetzen, verwenden Sie die Funktion „Vergleichen“ mit der entsprechenden Option für den Groß-/Kleinschreibungsvergleich.
    • Schließlich GetKeyHashakzeptiert die statische Funktion den extrahierten Schlüssel und gibt seinen Hashwert zurück. Da bei MatchesFunktionen die Groß-/Kleinschreibung beachtet wird, GetKeyHashmuss auch bei ihnen die Groß-/Kleinschreibung beachtet werden. Die Groß-/Kleinschreibung berücksichtigende FCrcFunktion berechnet den Hashwert der Schlüsselzeichenfolge.

Da die Struktur nun TMapdas erforderliche Verhalten erfüllt, können Instanzen davon erstellt werden.

TMap<
    FMyStruct,
    int32,
    FDefaultSetAllocator,
    TMyStructMapKeyFuncs<int32>
> MyMapToInt32;

 // Add some elements
 MyMapToInt32.Add(FMyStruct(3.14f), 5);
 MyMapToInt32.Add(FMyStruct(1.23f), 2);

 // MyMapToInt32 == [
 //  {
 //      Key:{
 //          UniqueID:"D06AABBA466CAA4EB62D2F97936274E4",
 //          SomeFloat:3.14f
 //      },
 //      Value:5
 //  },
 //  {
 //      Key:{
 //          UniqueID:"0661218447650259FD4E33AD6C9C5DCB",
 //          SomeFloat:1.23f
 //      },
 //      Value:5
 //  }
 // ]

TMapAngenommen, zwei Elemente Matcheswerden mithilfe von gleich verglichen, geben sie GetKeyHashdenselben Wert zurück. Darüber hinaus gelten Änderungen an den Schlüsseln vorhandener Kartenelemente, die die Ergebnisse einer dieser Funktionen ändern würden, als undefiniertes Verhalten, da sie dazu führen würden, dass sich das interne Hashing der Karte ändert. Ungültig. Diese Regeln gelten auch bei Verwendung der standardmäßigen KeyFuncs-Operatoren ==undGetKeyHash

10. Andere

10.1 GetAllocatedSize

Gibt die von diesem Container zugewiesene Speichermenge zurück. Es wird nur die direkt vom Container zugewiesene Größe zurückgegeben, nicht das Element selbst.

10.2 CountBytes

Zählen Sie die Anzahl der Bytes, die zum Serialisieren dieses Arrays erforderlich sind. Eingabe ist ein FArchive-Objekt.

zu guter Letzt

Dieser Artikel fasst einige gängige APIs von TMap in Kombination mit offiziellen Dokumenten zusammen. Sollten Fehler auftreten, korrigieren Sie diese bitte.

Referenz

おすすめ

転載: blog.csdn.net/qq_52179126/article/details/130712877