C ++でSTLコンテナーを操作するのは初めてで、Googleでさまざまな例を見ていると、ベクトルとセットが宣言される方法に何かが気づきました。
クラスAがあり、そのような要素をベクトルに格納する場合は、Aオブジェクトへのポインターを使用します(以下を参照)。セットの場合は、宣言で実際のオブジェクトを使用します。これを行う特別な理由があるのか、それとも私が見た例で起こっているのか疑問に思いました。
vector<*A> cont1;
set<A> cont2;
ほとんどの場合、ポインタ/スマートポインタではなく、自動保存期間のオブジェクトのコンテナを使用することになります。そのようなコンテナが醜いメモリ管理を処理するからです。
std::vector<A>
ほとんどの場合、単純で十分です。std::vector<A*>
これらは、代わりに使用する必要がある非常にまれな状況です。このような状況の一例は、このコンテナーの要素を使用しながら実行時のポリモーフィズムを実現する必要がある場合です。別の例としては、コピーにコストがかかる場合に発生する可能性のあるパフォーマンスの問題が原因でポインターを使用する場合A
があります。もう1つの理由は、オブジェクトのスライスを回避することです。
ポインタのコンテナを使用する本当に正当な理由がない限り、常にオブジェクトのコンテナを使用することをお勧めします。また、ポインターを保持する必要がある場合でも、代わりにスマートポインターを使用してください。
関連する質問:
C ++で動的に割り当てられたオブジェクトへのポインターのベクトルを使用するときにメモリリークを回避するにはどうすればよいですか?
C ++:オブジェクトのベクトルと新しいオブジェクトへのポインターのベクトル?
私はこれが一般的な慣習であることに気づいていません。
ただし、これを行う理由として考えられるのは、vector
サイズを変更すると、含まれているオブジェクトをメモリ内で移動できるためです。含まれているオブジェクトが他のオブジェクトへのポインタを与える場合、そのthis
ポインタは。の後に無効になる可能性がありますresize
。ポインタを格納し、メモリを自分で管理することで、オブジェクトはこれに悩まされることはありません。
を使用するset
と、セットがツリーとして実装される傾向があるため、同じ動作は観察されません。ただし、注意してください。C++標準ライブラリがこれについて保証するものではないと思います...
作者がこれを悪用しようとしている場合、set
彼らはカプセル化のルールを悪用しています。そうでない場合は、提供した2つの例は無関係である可能性があります。ポインタをコンテナに格納する(または格納しない)理由は他にもたくさんあり、自由に選択できます。
それはあなたが遭遇した単なる例です。オブジェクト自体からポインタ、関数ポインタまで、あらゆるものをベクトルに格納できます。他のベクトルをベクトルに格納して、多次元ベクトルを定義することもできます。
// define 4x4 vector
vector< vector<int> > vec(4, vector<int>(4));
vec[i][j] = a; // write
int b = vec[i][j]; // read
vector<A*> cont1;
cont1.push_back( new A( whatever ) );
vector<A> cont2;
cont2.push_back( A( whatever ) );
それはあなたが持っているユースケースに依存します。オブジェクトまたはポインタを保存しますか?
最初の例では各オブジェクトを手動で移動する必要がありますがdelete
、2番目の例では削除を処理することに注意してください。何をしているのかわからない場合は、可能な限り2番目を使用してください。また、割り当て(など)も安全になります。
何を保存したいかによります。
std::vector<A*> myVector;
...Aタイプへのポインタを格納するベクトルを作成します。
std::set<A> mySet;
...Aタイプの実際のインスタンスを格納するセットを作成します。
実際のインスタンスをベクターに簡単に保存できます。
std::vector<A> myVector;
またはセット内のポインタ:
std::set<A*> mySet;
セットとベクトルの本当の違いは、セットにはすべて固有の要素が含まれており、その操作の実行時間が異なることです。それらはまったく同等ではありません!
違いの理由は、同じであるが異なる場所に格納されている2つの動的に割り当てられたオブジェクトを持つことができるためです。これを行う場合:
A a,b;
std::vector<A> myVector;
myVector.push_back(a);
myVector.push_back(b);
その場合、myVectorには2つの要素が含まれますが、次の場合です。
A a,b;
std::set<A> mySet;
mySet.insert(a);
mySet.insert(b);
mySetには1つだけ含まれます。ポインタを使用した場合、これは当てはまりません。
さらに、(他の人が指摘しているように)ベクターで使用するアイテムを動的に割り当てる理由は、挿入のオーバーヘッドを減らすためです。
乾杯!
ベクトルは、コピー可能なものをすべて保持できる単純なコンテナです。したがって、必要に応じて、オブジェクトまたはオブジェクトへのポインタをその中に配置できます。
セットにポインタを含めることもできますが、通常、そうすることはあまり意味がありません。セットは順序付けられたコンテナーです。つまり、セットを作成するときに、比較関数を指定する必要があります。指定しない場合は、デフォルトの比較関数( )が使用されます。これは、定義std::less<>
するセットに格納しているものに依存します。operator<
ポインタをと比較できるため、これは実際にはポインタで機能するように見えますが、ポインタ<
が指すオブジェクトではなくポインタを比較するため、セットはメモリ内のオブジェクトの相対的な位置によって並べ替えられます。