1

これは、次のようなもので構成される関数があると言う私の質問です。

void function() {  
    entity e; //entity is just a class  
    entities.push_back(e); //entities is a vector of entity objects  
}

ここが私を悩ませているものです。'e' には、別のオブジェクトへのポインターが含まれています。エンティティのデストラクタが呼び出されると、そのポインタが削除されます。「e」とエンティティ内のエンティティの両方が同じ場所を指しているため、エンティティからそのポインタに何かをすると (関数の外で) エラーが発生します。戻ってきた。これを修正する最善の方法は何ですか?

4

4 に答える 4

5

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 に達した場合にのみ破棄されます。

于 2013-09-21T17:37:49.773 に答える
3

これは、3 つのルールに違反したためです。デストラクタがある場合は、ほぼ確実にコピー コンストラクタと代入演算子も必要です。

もちろん、ポインターを処理する最善の方法は、ポインターをまったく持たない方法を見つけることです (「ゼロの規則」)。そのような状況では、コンパイラによって生成されたデストラクタ、コンストラクタ、および代入演算子がリソースを管理します。あなたのために自動的に。

于 2013-09-21T17:28:57.203 に答える
3

を含むように共有オブジェクトへのポインターを変更するのshared_ptrは簡単な解決策です。

于 2013-09-21T17:27:21.780 に答える
0

エンティティ クラスにデストラクタがある場合は、3 つのルールによってコピーおよびコピー代入演算子も定義する必要があります。

残念ながら、これはおそらく、オブジェクトでポイントされているアイテムをコピーする必要があることを意味します。そのため、オブジェクトのコピーが破棄されたときに、後で他のコピーによって削除されるアイテムが削除されません。「残念ながら」ポイントされたアイテムの複製を作成することはしばしば望ましくないためです。この場合、設計上の難問があります -- Tom Kerr の提案 WRTshared_ptrは良い選択肢ですが。

別の解決策は、コピー コンストラクターを非公開にするか、(C++11) を使用してコピーを禁止し、代わりにポインターの配列を= delete作成することです (and )。entitypush_back(&e)

于 2013-09-21T17:36:38.597 に答える