C++ from Basics to Mastery — Part 10
Choosing an STL container and optional
The articles written on this blog were created with the goal of teaching. Also, the information in the article may be incorrect, so please be careful.
There are different types of data in the game, such as party lists, monster searches, spawn queues, and kill records. All data can be resolved with a single vector, but the code is clearer if you use a data structure that suits the purpose.
vector
std::vectoris a dynamic array that uses contiguous memory.
std::vector<int> damages;
damages.reserve(10);
damages.push_back(10);
damages.emplace_back(20);
for (int damage : damages)
{
std::cout << damage << '\n';
}
The element is[]orat()approach. at()checks the range, but[]is not checked.
If the capacity of the vector is insufficient, reallocation occurs by creating a new larger memory and moving existing elements. At this time, pointers, references, and iterators pointing to existing elements may be invalidated.
unordered_map
To quickly find an item by item ID, use a hash table.std::unordered_mapThis suits you.
std::unordered_map<int, Item> itemDatabase;
itemDatabase.emplace(1, Item{1, "Sword", 100});
auto iter = itemDatabase.find(1);
if (iter != itemDatabase.end())
{
std::cout << iter->second.name << '\n';
}
find()If it failsend()returns . You should not dereference an iterator without checking to see if it was found.
queue and stack
The queue is a FIFO structure where the value that comes in first comes out first. It fits well into the spawn queue.
if (!spawnQueue.empty())
{
auto monster = spawnQueue.front();
spawnQueue.pop();
}
The stack is a LIFO structure where the last value comes out first. It can be used to record or undo recent kills.
if (!killHistory.empty())
{
int lastMonsterId = killHistory.top();
killHistory.pop();
}
pop does not return a value. You must first get the value with front or top and then call pop.
optional
If there may be no search results, instead of a special error valuestd::optionalcan be used.
std::optional<Item> FindItem(int id) const
{
auto iter = itemDatabase.find(id);
if (iter == itemDatabase.end())
{
return std::nullopt;
}
return iter->second;
}
if (auto item = FindItem(1))
{
std::cout << item->name << '\n';
}
The return type reveals that there may or may not be a value. Blindly answering an empty optionalvalue()You should not call . You must first check for existence.
The criterion for choosing a data structure is not fashion, but intended use. An ordered list can be expressed as vector, key search as unordered_map, waiting order as queue, recent record as stack, and absence of value as optional.