[UE C++] TMap
Nach TArray
ist der am häufigsten verwendete Container in Unreal Engine 4 (UE4) TMap
. TMap
Ähnlich wie bei TSet
basiert ihre Struktur auf dem Hashing der Schlüssel. Aber im Gegensatz zu TSet
speichert 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: TMap
und TMultiMap
. Der Unterschied zwischen den beiden besteht darin, dass TMap
der Schlüssel eindeutig ist , während TMultiMap
mehrere identische Schlüssel darin gespeichert werden können. Wenn beim Hinzufügen eines neuen Schlüsselwerts in TMap
der 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 TMultiMap
kann 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
TPair
den 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
TMap
es 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
GetTypeHash
Funktionen 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 wieFHeapAllocator
und .TInlineAllocator
Der Sammlungszuordner (TSetAllocator
Klasse) 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
TMap
Vorlagenparameter, 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-GetTypeHash
Funktionen 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
TArray
im 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
TMap
Es ist unwahrscheinlich, dass die Elemente im Speicher zusammenhängend angeordnet werden, und dieTMap
einzige 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 wennTMap
Elemente 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 TArray
bei können Sie Emplace
stattdessen auch verwenden, Add
um zu verhindern, TMap
dass beim Einfügen temporäre Dateien erstellt werden. TArray
Im Gegensatz zu können Elemente jedoch nur über den Einzelparameter-Konstruktor in TMap eingefügt werden . Der Rückgabewert ist Add
derselbe 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
FindOrAdd
Gibt einen Verweis auf den Wert zurück, der dem angegebenen Key zugeordnet ist . Wenn der Schlüssel nicht in der TMap vorhanden ist, FindOrAdd
wird 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
FindRef
Gibt eine Kopie des mit dem angegebenen Schlüssel verknüpften Werts zurück. Wenn der angegebene Schlüssel nicht TMap
in 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 TMap
der Schlüssel nicht in gefunden wird FindOrAdd
und FindRef
erfolgreich 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 GenerateKeyArray
den gleichen Effekt wie in , aber in TMultiMap
wird 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 TMultiMap
existieren 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 TMap
und 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 Reserve
wird Speicher reserviert, ohne Elemente hinzuzufügen; durch Aufruf Reset
oder Aufruf mit einem Slack-Argument ungleich Null Empty
werden 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 Compact
die 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.
KeyInitType
und ElementInitType
sind 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
). GetTypeHash
Die Operatoren „and“ ==
gelten hier nicht, da der Operator ==
keine Daten jeglicher Art für allgemeine Zwecke ignorieren sollte, dies aber gleichzeitig tun muss ( UniqueID
andere Daten als diese ignorieren), um GetTypeHash
mit dem Verhalten konsistent zu sein, das ( GetTypeHash
) nur interessiert über UniqueID
Feld. Die folgenden Schritte helfen beim Erstellen benutzerdefinierter KeyFuncs für FMyStruct:
- Erstens die Vererbung
BaseKeyFuncs
, da sie dabei helfen kann, bestimmte Typen zu definieren, einschließlichKeyInitType
undElementInitType
.
BaseKeyFuncs
Verwenden 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.
- 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 istUniqueID
, kann die Funktion UniqueID direkt zurückgeben. - Die zweite statische Funktion ist
Matches
: Diese Funktion nimmt die Schlüssel zweier Elemente (GetSetKey
erhalten 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
GetKeyHash
akzeptiert die statische Funktion den extrahierten Schlüssel und gibt seinen Hashwert zurück. Da beiMatches
Funktionen die Groß-/Kleinschreibung beachtet wird,GetKeyHash
muss auch bei ihnen die Groß-/Kleinschreibung beachtet werden. Die Groß-/Kleinschreibung berücksichtigendeFCrc
Funktion berechnet den Hashwert der Schlüsselzeichenfolge.
- Der erste besteht darin
Da die Struktur nun TMap
das 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
// }
// ]
TMap
Angenommen, zwei Elemente Matches
werden mithilfe von gleich verglichen, geben sie GetKeyHash
denselben 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.