C++ は「コピーベース」の言語であり、たとえば のコンテナーは、指定したエンティティのコピーEntity
をコンテナー内に配置します。
コピーは多くの場所で C++ で作成されるため、クラスでコピーを正しくサポートするか、完全に禁止することをお勧めします。
クラスに他のデータへのポインタが含まれています。そのクラスのインスタンスのコピーを作成するとどうなるでしょうか? ポインターのコピーに問題がない場合、まだ存在するコピーが削除されたオブジェクトを指しているため、デストラクタでポイントされたオブジェクトを削除することは明らかにできません。
この種の間違いを避けるのに役立つ簡単なルールがあり、「3 つのルール」として知られています。どちらかを明示的にコーディングした場合
あなたのクラスでは、おそらく3つすべてが必要です。
この場合、(指定されたオブジェクトを削除するため) デフォルトのものではないデストラクタがあるため、コピーの構築または割り当ての場合に何をすべきかを伝える必要もあります。
そのクラスをコピー不可にしたい場合は、それを確認してください
struct Entity {
Object *o;
Entity(Object *o) : o(o) {
...
}
~Entity() {
delete o;
}
private:
// Taboo... this should just never happen!!!
// Here is a declaration, but no implementation will be written
Entity(const Entity& other); // Copy constructor
Entity& operator=(const Entity&); // Assignment
};
禁止された操作を宣言private
すると、ユーザーコードがそれらを呼び出さないことが保証され(コンパイル時のエラーになります)、実装を提供せずに宣言するだけで、クラスコード自体でさえ誤ってそれらを呼び出さないことが保証されます(あなたは得るでしょうリンク時エラー)。
ただし、この特定のケースでは、コードがEntity
コンテナー内にインスタンスを配置することを禁止します (コンテナー内の要素をコピーする必要があります)。Entity
コンテナー内にポインターを配置することもできます (ポインターはコピーできるため、std::vector<Entity *>
forentities
は有効です) が、オブジェクトの正しい有効期間を処理する責任があります (誰がデストラクタを呼び出す必要があり、いつそれが発生する必要がありますか?)。
一方、クラス内のデータへのポインターがあり、クラスのインスタンスのコピーを作成できるようにする場合は、次のいずれかを実行できます。
- 指摘されたデータもコピーする
- 指摘されたデータを異なるインスタンス間で共有する
2 番目の解決策の一般的なアプローチは、「参照カウント」ポインターを使用することです。つまり、ポイントされたデータは、それを参照しているポインターの数を「認識」しており、このカウントが 0 に達した場合にのみ破棄されます。