コードの効率は実際には影響を受けません (ベクター ランダム アクセスのコストは基本的に何もありません)。注意すべきことは、ベクター データ構造の悪用です。
これほど複雑なものに対して、クラスに対してベクトルを使用する必要がある理由はほとんどありません。適切に定義されたインターフェースを持つクラスは、コードをより効率的にするわけではありませんが、将来的にはメンテナンスがずっと簡単になります。
現在のソリューションも、未定義の動作に陥る可能性があります。たとえば、投稿したコードを見てください。
Block b = rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d];
pos.a
、pos.b
、pos.c
によって参照されるベクトル インデックスpos.d
がこれらのベクトルの 1 つに存在しない場合はどうなるでしょうか。未定義の動作に陥り、アプリケーションがセグメンテーション違反になる可能性があります (運が良ければ)。
これを修正するには、オブジェクトを取得する前にすべてのベクトルのサイズを比較する必要がありBlock
ます。
例えば
Block b;
if ((pos.a < rawSheets.size()) &&
(pos.b < rawSheets[pos.a].countries.size()) &&
(pos.c < rawSheets[pos.a].countries[pos.b].cities.size()) &&
(pos.d < rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks.size()))
{
b = rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d];
}
ブロックが必要になるたびに本当にそうするつもりですか?!!
あなたはそれを行うことができます、または少なくともクラスにまとめることができます...
例:
class RawSheet
{
Block & FindBlock(const Pos &pos);
std::vector<Country> m_countries;
};
Block & RawSheet::FindBlock(const Pos &pos)
{
if ((pos.b < m_countries.size()) &&
(pos.c < m_countries[pos.b].cities.size()) &&
(pos.d < m_countries[pos.b].cities[pos.c].blocks.size()))
{
return m_countries[pos.b].cities[pos.c].blocks[pos.d];
}
else
{
throw <some exception type here>;
}
}
次に、次のように使用できます。
try
{
Block &b = rawSheets[pos.a].FindBlock(pos);
// Do stuff with b.
}
catch (const <some exception type here>& ex)
{
std::cout << "Unable to find block in sheet " << pos.a << std::endl;
}
少なくとも、RawSheet
クラス内でベクトルを引き続き使用できますが、メソッド内にあるため、他の場所のコードを変更することなく、後日ベクトルの乱用を削除できます (「デメテルの法則」を参照)!