JavaまたはC#参照(C++参照よりもC++ポインターに似ています)とは異なり、C ++の参照はポインターと同じくらい「ダム」です。つまり、オブジェクトの参照を取得し、そのオブジェクトをメモリ内で移動すると、その参照ははもう有効ではありません。
参照cはまだ有効ですか(またはさらに良いことに、有効であることが保証されています)?
あなたが説明している場合、標準ベクトルは、ベクトルの内容が変更されたとき(アイテムの削除、ベクトルのサイズ変更など)に、含まれているオブジェクトをメモリ内の同じ場所に保持することを保証されません。
これにより、イテレータと、含まれているオブジェクトへのポインタ/参照の両方が無効になります。
そうでない場合は、安全を確保するために、常に参照からコピーを作成する必要がありますか?
適切なオブジェクトを「ポイント」し続けるには複数の方法があり、それらはすべて、あるレベルの間接参照を意味します。
フル/バリューコピー
最も簡単なのは、MyClassの完全なコピーを作成することです。
vector<MyClass> x ;
x.push_back(a) ;
x.push_back(b) ;
MyClass c = x[1] ; // c is a full copy of b, not a reference to b
x.erase(x.begin()) ;
適切なコンテナを使用する
2番目に簡単な方法はstd::list
、要素の挿入と削除用に特別に設計されたaを使用することです。これは、含まれているオブジェクトを変更したり、それらへのポインター、参照、またはイテレーターを無効にしたりしません。
list<MyClass> x ;
x.push_back(a) ;
x.push_back(b) ;
list<MyClass> it = x.begin() ;
++it ;
MyClass & c = *it ;
x.erase(x.begin()) ;
ポインタの使用(安全ではない)
もう1つは、オブジェクトの代わりにへのstd::vector<MyClass *>
ポインタを含むを作成することです。これにより、(余分な間接参照のために)わずかに異なる表記法で、ポイントされたオブジェクトへのポインターまたは参照を保持できるようになります。MyClass
MyClass
vector<MyClass *> x;
x.push_back(a); // a being a MyClass *
x.push_back(b); // b being a MyClass *
MyClass * c = x[1]; // c points to the same object as b
x.erase(x.begin()); // note that a will still need separate deallocation
オブジェクトaとbの明確な(コンパイラに関する限り)所有者がいないため、これは安全ではありません。つまり、オブジェクトが不要になったときにオブジェクトの割り当てを解除する明確なコードがないことを意味します(これがメモリリークの発生方法です)。 CおよびC++で)
したがって、この方法を使用する場合は、コードが適切にカプセル化されていることを確認し、メンテナンスの予期せぬ事態を避けるために可能な限り小さくしてください。
スマートポインタの使用(より安全)
より良いものは、スマートポインタを使用することです。たとえば、C ++ 11(またはブースト)を使用しshared_ptr
ます。
vector< shared_ptr<MyClass> > x;
x.push_back(a); // a being a shared_ptr<MyClass>
x.push_back(b); // b being a shared_ptr<MyClass>
shared_ptr<MyClass> c = x[1]; // c points to the same object as b
x.erase(x.begin()); // No deallocation problem
さて、を使用していて、shared_ptr
について何も知らないweak_ptr
場合は、問題があるので、そのギャップを埋める必要があります。
スマートポインタの使用2(より安全)
unique_ptr
別の解決策は、ポイントされたオブジェクトの排他的な所有者であるC++11を使用することです。したがって、ポインタまたはポインタオブジェクトへの参照が必要な場合は、生のポインタを使用する必要があります。
vector< unique_ptr<MyClass> > x;
x.push_back(a); // a being a unique_ptr<MyClass>
x.push_back(b); // b being a unique_ptr<MyClass>
MyClass * c = x[1].get(); // c points to the same object as b
x.erase(x.begin()); // No deallocation problem
ここで、上記の。の場合とは異なり、ベクトルはオブジェクトの一意の所有者であることに注意してくださいsmart_ptr
。
結論
C ++でコーディングしているため、問題に適した方法を選択する必要があります。
ただし、最初に、ポインターによって追加される間接参照のレベル、ポインターの機能、およびC ++参照の機能(およびC#/ Java参照ではない理由)を確実に理解する必要があります。