C++ 基礎からマスターまで — 第10回
STLコンテナとオプションの選択
本ブログ作成文は、講義を目指して製作されました。 また、作成された文章の情報も間違っている可能性がありますので、ご注意ください。
ゲームにはパーティーリスト、モンスター検索、スポーンキュー、処置記録のように、異なる形態のデータが存在する。 すべてのデータをベクトルとして解決することはできますが、目的に合ったデータ構造を書く方がコードがより明確です。
vector
std::vectorは連続したメモリを使用する動的配列です。
std::vector<int> damages;
damages.reserve(10);
damages.push_back(10);
damages.emplace_back(20);
for (int damage : damages)
{
std::cout << damage << '\n';
}
元素は[]またはat()に近づく。 at()銀の範囲を調べますが、[]は点検しない。
vectorの容量が不足すると、より大きなメモリを新しくして既存元素を移動する再割り当てが発生する。 このとき、既存元素を指していたポインタ、参照、イテレータは無効化されることがある。
unordered_map
アイテムIDでアイテムをすばやく見つけるには、ハッシュテーブルstd::unordered_mapこの似合う。
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()が失敗した場合end()を返します。 見つけたことを確認せずに反復子を逆参照してはならない。
queue と stack
queueは、最初に入った値が最初に出るFIFO構造です。スポーンキューによく合う。
if (!spawnQueue.empty())
{
auto monster = spawnQueue.front();
spawnQueue.pop();
}
stackは最後に入った値が最初に出るLIFO構造です。最近の処置記録や取り消しに使用することができる。
if (!killHistory.empty())
{
int lastMonsterId = killHistory.top();
killHistory.pop();
}
popは値を返しません。 frontまたはtopで最初に値を取得し、popを呼び出す必要があります。
optional
検索結果がない場合は、特別なエラー値の代わりにstd::optionalを使うことができる。
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';
}
値があってもなくてもよいという事実が戻り型にあらわれる。 空のoptionalに無作為value()を呼び出さないでください。まず、存在するかどうかを確認する必要があります。
データ構造を選択する基準は流行ではなく使用目的である。 順序付きリストはベクトル、キー検索はunordered_map、待機順序はキュー、最近のレコードはスタック、値の不在はオプションです。