多くのオブジェクトへのポインタを保持する配列を作成したいのですが、保持するオブジェクトの数が事前にわかりません。つまり、配列にメモリを動的に割り当てる必要があります。私は次のコードを考えました:
ants = new *Ant[num_ants];
for (i=1;i<num_ants+1;i++)
{
ants[i-1] = new Ant();
}
ここで、ants
はAnt **ants;
として定義され、Ant
はクラスです。
うまくいきますか?
うまくいきますか?
はい。
ただし、可能であれば、ベクトルを使用する必要があります。
#include <vector>
std::vector<Ant*> ants;
for (int i = 0; i < num_ants; ++i) {
ants.Push_back(new Ant());
}
動的に割り当てられた配列を使用する必要がある場合は、次の構文を使用します。
typedef Ant* AntPtr;
AntPtr * ants = new AntPtr[num_ants];
for (int i = 0; i < num_ants; ++i) {
ants[i] = new Ant();
}
しかし、すべてを忘れてください。手動のメモリ管理が必要なため、コードはまだ良いものではありません。これを修正するには、コードを次のように変更します。
std::vector<std::unique_ptr<Ant>> ants;
for (auto i = 0; i != num_ants; ++i) {
ants.Push_back(std::make_unique<Ant>());
}
そして何よりも、これは単純に次のようになります。
std::vector<Ant> ants(num_ants);
std::vector<Ant> ants(num_ants);
ants.resize(new_num_ants);
本当にアイテムにpointersを保持する必要がありますか?値でオブジェクトを使用できる場合、ベクトルを使用するのがはるかに簡単な方法です:std::vector<Ant> ants(num_ants);
。そうすれば、ループを作成する必要がなくなるだけでなく、生のポインタやその他のオブジェクト管理アイテムからのメモリリークを心配する必要もなくなります。
APIを満たすためにオブジェクトポインターが必要な場合でも、外部コンテナーにvector
を使用して、オブジェクトを手動で割り当てることができます。
struct CreateAnt
{
Ant* operator()() const { return new Ant; }
};
std::vector<Ant*> ants(num_ants); // Create vector with null pointers.
std::generate(ants.begin(), ants.end(), CreateAnt());
はい、それは一般的な考えです。ただし、代替手段があります。ポインタの配列が必要ですか?クラスAnt
のオブジェクトの配列で十分な場合があります。配列を割り当てる必要があるだけです:
Ant *ants = new Ant[num_ants];
一般に、配列を使用するよりもstd::vector
を使用することをお勧めします。ベクトルは必要に応じて拡張でき、メモリ管理を処理します。
投稿したコードでは、ants
の各要素をループで削除してから、配列自体delete [] ant
を削除する必要があります。 delete
とdelete []
の違いに注意してください。
もう1つ、C++の配列インデックスは0ベースであるため、次の規則を使用して要素を反復処理します。
for (i=0; i<num_ants; i++)
{
ants[i] = new Ant();
}
これにより、コードがはるかに読みやすくなります。
std::vector<Ant*> ants( num_ants );
for ( int i = 0; i != num_ants; ++ i ) {
ants[i] = new Ant;
}
または、事前に何件あるかわからない場合:
std::vector<Ant*> ants;
while ( moreAntsNeeded() ) {
ants.Push_back( new Ant );
}
一方、Ant
がエンティティタイプなのか値なのかを自問する必要があると思います。値の場合は、ポインタと動的割り当てをスキップすることをお勧めします。エンティティタイプの場合は、オブジェクトの有効期間と、いつ、どこで削除されるかを考慮する必要があります。