Choose your operating system:
Windows
macOS
Linux
After
TArray
, the most commonly used container in
Unreal Engine 4
(UE4) is
TMap
.
TMap
is similar to
TSet
in that its structure is based on hashing keys. However, unlike
TSet
, this container stores data as key-value pairs (
TPair<KeyType, ValueType>
), using keys only for storage and retrieval.
There are two types of map:
TMap
and
TMultiMap
. The difference between these two is that
TMap
keys are unique, while
TMultiMap
supports storing multiple, identical keys. When adding a new key-value pair to a
TMap
with a key that matches an existing pair, the new pair will replace the old one. In a
TMultiMap
, the container will store both the new pair and the old.
TMap
In a
TMap
, key-value pairs are treated as the element type of the map as if each pair were an individual object. In this document, element means a key-value pair, while individual components are referred to as the element's key or the element's value. The element type is actually a
TPair<KeyType, ElementType>
, though it should be rare to need to refer to the
TPair
type directly.
Like
TArray
,
TMap
is a homogeneous container, meaning that all of its elements are strictly the same type.
TMap
is also a value type, and supports the usual copy, assignment, and destructor operations, as well as strong ownership of its elements, which will be destroyed when the map is destroyed. The key and value must also be value types.
TMap
is a hashing container, which means that the key type must support the
GetTypeHash
function and provide an
operator==
for comparing keys for equality. Hashing is covered in more detail later.
TMap
can also take an optional allocator to control the memory allocation behavior. However, unlike
TArray
, these are set allocators rather than the standard UE4 allocators like
FHeapAllocator
and
TInlineAllocator
. Set allocators, (class
TSetAllocator
), define how many hash buckets the map should use and which standard UE4 allocators should be used for hash and element storage.
The final
TMap
template parameter is
KeyFuncs
, which tells the map how to retrieve the key from the element type, how to compare two keys for equality and how to hash the key. These have defaults which will just return a reference to the key, use
operator==
for equality, and call the non-member
GetTypeHash
function for hashing. If your key type supports these functions, you can use it as a map key without supplying a custom
KeyFuncs
.
Unlike
TArray
, the relative order of
TMap
elements in memory is not reliable or stable, and iterating over the elements is likely to return them in a different order from the order in which they were added. Elements are also unlikely to be laid out contiguously in memory. The backing data structure of a map is a sparse array, which is an array that efficiently supports gaps between its elements. As elements are removed from the map, gaps in the sparse array will appear. Adding new elements into the array can then fill these gaps. However, even though
TMap
doesn't shuffle elements to fill gaps, pointers to map elements may still be invalidated, as the entire storage can be reallocated when it is full and new elements are added.
Creating and Filling a Map
You can create a
TMap
like this:
TMap<int32, FString> FruitMap;
FruitMap
is now an empty
TMap
of strings that are identified by integer keys. We have specified neither an allocator nor a
KeyFuncs
, so the map will do standard heap allocation and compare the key (of type
int32
) using
operator==
and hash it using
GetTypeHash
. No memory has been allocated at this point.
The standard way to populate a map is to call the
Add
function with a key and a value:
FruitMap.Add(5, TEXT("Banana"));
FruitMap.Add(2, TEXT("Grapefruit"));
FruitMap.Add(7, TEXT("Pineapple"));
// FruitMap == [
// { Key: 5, Value: "Banana" },
// { Key: 2, Value: "Grapefruit" },
// { Key: 7, Value: "Pineapple" }
// ]
While the elements are listed here in the order of insertion, there is no guarantee as to their actual order in memory. For a new map, they are likely to be in order of insertion, but as more insertions and removals happen, it becomes increasingly unlikely that new elements will appear at the end.
This is not a
TMultiMap
, so keys are guaranteed to be unique. The following is the result of attempting to add a duplicate key:
FruitMap.Add(2, TEXT("Pear"));
// FruitMap == [
// { Key: 5, Value: "Banana" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" }
// ]
The map still contains three elements, but the previous "Grapefruit" value with a key of 2 has been replaced with "Pear".
The
Add
function can accept a key without a value. When this overloaded
Add
is called, the value will be default-constructed:
FruitMap.Add(4);
// FruitMap == [
// { Key: 5, Value: "Banana" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "" }
// ]
Like
TArray
, we can also use
Emplace
instead of
Add
to avoid the creation of temporaries when inserting into the map:
FruitMap.Emplace(3, TEXT("Orange"));
// FruitMap == [
// { Key: 5, Value: "Banana" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "" },
// { Key: 3, Value: "Orange" }
// ]
Here, the key and value are passed directly to their respective type constructors. While this isn't meaningful for the
int32
key, it does avoid the creation of a temporary
FString
for the value. Unlike
TArray
, it's only possible to emplace elements into a map with single-argument constructors.
You can also merge two maps with the
Append
function, which will move all elements from one map into the other:
TMap<int32, FString> FruitMap2;
FruitMap2.Emplace(4, TEXT("Kiwi"));
FruitMap2.Emplace(9, TEXT("Melon"));
FruitMap2.Emplace(5, TEXT("Mango"));
FruitMap.Append(FruitMap2);
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
// FruitMap2 is now empty.
In the above example, the resulting map is equivalent to using
Add
or
Emplace
to add each element of
FruitMap2
individually, emptying
FruitMap2
when the process is complete. This means that any element from
FruitMap2
that shares its key with an element already in
FruitMap
will replace that element.
If you mark the
TMap
with the
UPROPERTY
macro and one of the "editable" keywords (
EditAnywhere
,
EditDefaultsOnly
, or
EditInstanceOnly
), you can
add and edit elements in the Editor
.
UPROPERTY(Category = MapsAndSets, EditAnywhere)
TMap<int32, FString> FruitMap;
Iteration
Iteration over
TMaps
is similar to
TArrays
. You can use C++'s ranged-for feature, remembering that the element type is a
TPair
:
for (auto& Elem : FruitMap)
{
FPlatformMisc::LocalPrint(
*FString::Printf(
TEXT("(%d, \"%s\")\n"),
Elem.Key,
*Elem.Value
)
);
}
// Output:
// (5, "Mango")
// (2, "Pear")
// (7, "Pineapple")
// (4, "Kiwi")
// (3, "Orange")
// (9, "Melon")
You can also create iterators with the
CreateIterator
and
CreateConstIterators
functions.
CreateIterator
will return an iterator with read-write access, while
CreateConstIterator
returns a read-only iterator. In either case, you can use the
Key
and
Value
functions of these iterators to examine the elements. Printing the contents of our example "fruit" map using iterators would look like this:
for (auto It = FruitMap.CreateConstIterator(); It; ++It)
{
FPlatformMisc::LocalPrint(
*FString::Printf(
TEXT("(%d, \"%s\")\n"),
It.Key(), // same as It->Key
*It.Value() // same as *It->Value
)
);
}
Queries
To find out how many elements are currently in the map, call the
Num
function.
int32 Count = FruitMap.Num();
// Count == 6
In order to determine whether or not a map contains a specific key, call the
Contains
function, as follows:
bool bHas7 = FruitMap.Contains(7);
bool bHas8 = FruitMap.Contains(8);
// bHas7 == true
// bHas8 == false
If you know that your map contains a certain key, you can look up the corresponding value with
operator[]
, using the key as the index. Doing this with a non-const map will return a non-const reference, while a const map will return a const reference.
operator[]
FString Val7 = FruitMap[7];
// Val7 == "Pineapple"
FString Val8 = FruitMap[8];
// Assert!
If you are unsure whether or not your map contains a key, you could check with the
Contains
function, and then use
operator[]
. However, this is suboptimal, since a successful retrieval involves two lookups on the same key. The
Find
function combines these behaviors with a single lookup.
Find
returns a pointer to the value of the element if the map contains the key, or a null pointer if it does not. Calling
Find
on a const map will cause the pointer it returns to be const as well.
FString* Ptr7 = FruitMap.Find(7);
FString* Ptr8 = FruitMap.Find(8);
// *Ptr7 == "Pineapple"
// Ptr8 == nullptr
Alternately, to ensure that you get a valid result from your query, you can use
FindOrAdd
or
FindRef
.
FindOrAdd
will return a reference to the value associated with the key you provide. If the key was not in the map,
FindOrAdd
will return a newly-created element, with your key and the default-contructed value, that it will also add to the map. Because it can potentially modify the map,
FindOrAdd
is only available for non-const maps.
FindRef
, despite its name, will return a copy of the value associated with your key, or a default-constructed value if your key is not found in the map.
FindRef
does not create a new element, and thus is available for use with both const and non-const maps. Because
FindOrAdd
and
FindRef
succeed even when the key isn't found in the map, you can safely call them without the usual safety procedures like checking
Contains
in advance, or null-checking the return value.
FString& Ref7 = FruitMap.FindOrAdd(7);
// Ref7 == "Pineapple"
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
FString& Ref8 = FruitMap.FindOrAdd(8);
// Ref8 == ""
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" },
// { Key: 8, Value: "" }
// ]
FString Val7 = FruitMap.FindRef(7);
FString Val6 = FruitMap.FindRef(6);
// Val7 == "Pineapple"
// Val6 == ""
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" },
// { Key: 8, Value: "" }
// ]
Because
FindOrAdd
can add new entries to the map, as it does when initializing
Ref8
in our example, previously-obtained pointers (from
Find
) or references (from
FindOrAdd
) could become invalid. This is a result of the addition operation allocating memory and moving existing data if the map's backend storage needs to expand to contain the new element. In the example above,
Ref7
may be invalidated after
Ref8
after the call to
FindOrAdd(8)
.
The
FindKey
function performs a reverse lookup, meaning that a supplied value is matched to a key, and returns a pointer to the first key that's paired to the provided value. Searches for a value that isn't present in the map will return a null key.
const int32* KeyMangoPtr = FruitMap.FindKey(TEXT("Mango"));
const int32* KeyKumquatPtr = FruitMap.FindKey(TEXT("Kumquat"));
// *KeyMangoPtr == 5
// KeyKumquatPtr == nullptr
Lookups by value are slower (linear time) than lookups by key. This is because the map is sorted by key, not by value. In addition, if a map has multiple keys with the same value,
FindKey
may return any of them.
The
GenerateKeyArray
and
GenerateValueArray
functions populate a
TArray
with a copy of all the keys and values respectively. In both cases, the array being passed is emptied before population, so the resulting number of elements will always equal the number of elements in the map.
TArray<int32> FruitKeys;
TArray<FString> FruitValues;
FruitKeys.Add(999);
FruitKeys.Add(123);
FruitMap.GenerateKeyArray (FruitKeys);
FruitMap.GenerateValueArray(FruitValues);
// FruitKeys == [ 5,2,7,4,3,9,8 ]
// FruitValues == [ "Mango","Pear","Pineapple","Kiwi","Orange",
// "Melon","" ]
Removal
Elements can be removed from maps by using the
Remove
function and providing the key of the element to remove. The return value is the number of elements that were removed, and can be zero if the map didn't contain any elements matching the key.
FruitMap.Remove(8);
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
Removing elements can leave holes in the data structure, which you can see when visualizing the map in Visual Studio's watch window, but they have been omitted here for clarity.
The
FindAndRemoveChecked
function can be used to remove an element from the map and return its value. The "checked" part of the name indicates that the map will call
check
(UE4's equivalent of
assert
) if the key does not exist.
FString Removed7 = FruitMap.FindAndRemoveChecked(7);
// Removed7 == "Pineapple"
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
FString Removed8 = FruitMap.FindAndRemoveChecked(8);
// Assert!
The
RemoveAndCopyValue
function is similar to
Remove
, but copies the value of the removed element out to a reference parameter. If the key you specified is not present in the map, the output parameter will be unchanged and the function will return
false
.
FString Removed;
bool bFound2 = FruitMap.RemoveAndCopyValue(2, Removed);
// bFound2 == true
// Removed == "Pear"
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
bool bFound8 = FruitMap.RemoveAndCopyValue(8, Removed);
// bFound8 == false
// Removed == "Pear", i.e. unchanged
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
Finally, you can remove all elements from the map with the
Empty
or
Reset
functions.
TMap<int32, FString> FruitMapCopy = FruitMap;
// FruitMapCopy == [
// { Key: 5, Value: "Mango" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
FruitMapCopy.Empty(); // We could also have called Reset() here.
// FruitMapCopy == []
Empty
and
Reset
are similar, but
Empty
can take a parameter to indicate how much slack to leave in the map, while
Reset
Sorting
A
TMap
can be sorted. After sorting, iteration over the map will present the elements in sorted order, but this behavior is only guaranteed until the next time you modify the map. Sorting is unstable, so equivalent elements in a MultiMap may appear in any order.
You can sort by key or by value using the
KeySort
or
ValueSort
functions, respectively. Both functions take a binary predicate which specifies the sort order.
FruitMap.KeySort([](int32 A, int32 B) {
return A > B; // sort keys in reverse
});
// FruitMap == [
// { Key: 9, Value: "Melon" },
// { Key: 5, Value: "Mango" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" }
// ]
FruitMap.ValueSort([](const FString& A, const FString& B) {
return A.Len() < B.Len(); // sort strings by length
});
// FruitMap == [
// { Key: 4, Value: "Kiwi" },
// { Key: 5, Value: "Mango" },
// { Key: 9, Value: "Melon" },
// { Key: 3, Value: "Orange" }
// ]
Operators
Like
TArray
,
TMap
is a regular value type, and can be copied with the standard copy constructor or assignment operator. Maps strictly own their elements, so copying a map is deep; the new map will have its own copy of the elements.
TMap<int32, FString> NewMap = FruitMap;
NewMap[5] = "Apple";
NewMap.Remove(3);
// FruitMap == [
// { Key: 4, Value: "Kiwi" },
// { Key: 5, Value: "Mango" },
// { Key: 9, Value: "Melon" },
// { Key: 3, Value: "Orange" }
// ]
// NewMap == [
// { Key: 4, Value: "Kiwi" },
// { Key: 5, Value: "Apple" },
// { Key: 9, Value: "Melon" }
// ]
TMap
supports move semantics, which can be invoked using the
MoveTemp
function. After a move, the source map is guaranteed to be empty:
FruitMap = MoveTemp(NewMap);
// FruitMap == [
// { Key: 4, Value: "Kiwi" },
// { Key: 5, Value: "Apple" },
// { Key: 9, Value: "Melon" }
// ]
// NewMap == []
Slack
Slack is allocated memory that doesn't contain an element. You can allocate memory without adding elements by calling
Reserve
, and you can remove elements without deallocating the memory they were using by calling
Reset
or by calling
Empty
with a non-zero slack parameter. Slack optimizes the process of adding new elements to the map by using pre-allocated memory instead of having to allocate new memory. It can also help with element removal since the system does not need to deallocate memory. This is especially efficient when you are emptying a map that you expect to repopulate immediately with the same number of elements or fewer.
TMap
does not provide a way of checking how many elements are preallocated the way the
Max
function in
TArray
does.
In this code, the
Reserve
function preallocates our map to contain up to ten elements.
FruitMap.Reserve(10);
for (int32 i = 0; i < 10; ++i)
{
FruitMap.Add(i, FString::Printf(TEXT("Fruit%d"), i));
}
// FruitMap == [
// { Key: 9, Value: "Fruit9" },
// { Key: 8, Value: "Fruit8" },
// ...
// { Key: 1, Value: "Fruit1" },
// { Key: 0, Value: "Fruit0" }
// ]
To remove all slack from a
TMap
, use the
Collapse
and
Shrink
functions.
Shrink
removes all slack from the end of the container, but this will leave any empty elements in the middle or at the start.
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" }
// ]
Shrink
only removed one invalid element in the code above because there was only one empty element at the end. To remove all slack, the
Compact
function should be called first, so that the empty spaces will be grouped together in preparation for
Shrink
.
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" }
// ]
KeyFuncs
As long as a type has an
operator==
and a non-member
GetTypeHash
overload, you can use it as a key type for a
TMap
without any changes. However, you may want to use types as keys without overloading those functions. In these cases, you can provide your own custom
KeyFuncs
. To create
KeyFuncs
for your key type, you must define two typedefs and three static functions, as follows:
-
KeyInitType
— Type used to pass keys around. -
ElementInitType
— Type used to pass elements around. -
KeyInitType GetSetKey(ElementInitType Element)
— Returns the key of an element. -
bool Matches(KeyInitType A, KeyInitType B)
— Returnstrue
ifA
andB
are equivalent,false
otherwise. -
uint32 GetKeyHash(KeyInitType Key)
— Returns the hash value ofKey
.
KeyInitType
and
ElementInitType
are typedefs to the normal passing convention of the key type and element type. Usually these will be a value for trivial types and a const reference for non-trivial types. Remember that the element type of a map is a
TPair
.
An example of a custom
KeyFuncs
might look like this:
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
features a unique identifier, as well as some other data that does not contribute to its identity.
GetTypeHash
and
operator==
would be inappropriate here, because
operator==
should not ignore any of the type's data for general-purpose usage, but would simultaneously need to do so in order to be consistent with the behavior of
GetTypeHash
, which only looks at the
UniqueID
field. The following steps will help to create a custom
KeyFuncs
for
FMyStruct
:
-
First, inherit
BaseKeyFuncs
, as it helpfully defines some types, includingKeyInitType
andElementInitType
.BaseKeyFuncs
takes two template parameters: the element type of the map, and the type of our key. As with all maps, the element type is aTPair
, takingFMyStruct
as itsKeyType
and the template parameter ofTMyStructMapKeyFuncs`as its
ValueType. The replacement
KeyFuncsis a template, so that you can specify
ValueTypeon a per-map basis, rather than needing to define a new
KeyFuncsevery time you want to create a
TMapkeyed on
FMyStruct. The second
BaseKeyFuncsargument is the type of the key, not to be confused with the
KeyTypefrom
TPair, the Key field of the element stores. Since this map should use
UniqueID(from
FMyStruct) as its key,
FString` is used here. -
Next, define the three required
KeyFuncs
static functions. The first isGetSetKey
, which returns the key for a given element type. Our element type isTPair
, and our key isUniqueID
, so the function can simply returnUniqueID
directly.The second static function is
Matches
, which takes the keys of two elements (retrieved byGetSetKey
), and compares them to see if they are equivalent. ForFString
, the standard equivalence test (operator==
) is case-insensitive; to replace this with a case-sensitive search, use theCompare
function with the appropriate case-comparison option. -
Finally, the
GetKeyHash
static function takes an extracted key and returns a hashed value for it. Because theMatches
function is case-sensitive,GetKeyHash
must also be. A case-sensitiveFCrc
function will calculate the hash value from the key string. -
Now that the structure supports the behaviors that
TMap
requires, you can create instances of it.
KeyFuncs
parameter is last, and this
TMap
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
assumes that two items that compare as equals using
Matches
will also return the same value from
GetKeyHash
. In addition, modifying the key of an existing map element in a way which will change the results from either of these functions is considered undefined behavior, as this will invalidate map's internal hash. These rules also apply to the overloads of
operator==
and
GetKeyHash
when using the default
KeyFuncs
Miscellaneous
The
CountBytes
and
GetAllocatedSize
functions estimate how much memory the internal array is currently utilizing.
CountBytes
takes an
FArchive
parameter, while
GetAllocatedSize
does not. These functions are typically used for stats reporting.
The
Dump
function takes an
FOutputDevice
and writes out some implementation information about the contents of the map. This function is usually used for debugging.