0

インスタンスが一緒に作成および削除される2つのクラスを作成しようとしています。1つのクラスは他のクラスのベースです。

class Interface;

class MyClass
{
friend class Interface;
private:
  MyClass() {}
public:
  static MyClass *NewInstance();
  Interface *ControlPanel;
};

class Interface : public MyClass
{
friend class MyClass;
private:
  Interface() {}
public:
  void Control1() {cout << "control1" << endl;}
  void Control2() {cout << "control2" << endl;}
  void Control3() {cout << "control3" << endl;}
};

インスタンスを作成および削除することになっている2つのメンバー関数は次のとおりです。

MyClass *MyClass::NewInstance()
{
  MyClass *inst = new MyClass;
  inst->ControlPanel = new Interface;
  return inst;
}

void DeleteMyClassInstance(MyClass *inst)
{
  delete inst->ControlPanel;
  inst->ControlPanel = 0;
  delete inst;
  inst = 0;
}

インスタンス作成プロセスを、インスタンスを作成する基本クラス()の関数を使用してリンクすることに成功しましたNewInstance()。ただし、削除関数(DeleteMyClassInstance())は機能しません(つまり、関数を呼び出した後でも両方inst1を使用できます)。inst1->ControlPanel

int main()
{
  MyClass *inst1 = MyClass::NewInstance();

  inst1->ControlPanel->Control1();

  DeleteMyClassInstance(inst1);

  inst1->ControlPanel->Control1();

  return 0;
}

しかし、main関数内に削除コードを配置すると、完全に機能します(inst1->ControlPanel->Control1()deleteステートメントの後に続くステートメントは機能しません。それが私が望むものです)。

int main()
{
  MyClass *inst1 = MyClass::NewInstance();

  inst1->ControlPanel->Control1();

  delete inst->ControlPanel;
  inst->ControlPanel = 0;
  delete inst;
  inst = 0;

  inst1->ControlPanel->Control1();

  return 0;
}

私の質問は、deleteステートメントをmain関数内に直接配置しても、別の関数内に配置してmainで使用しても機能しないのはなぜですか?DeleteMyClassInstance()関数内のコードがコンパイラーによって無視されるのはなぜですか?

4

2 に答える 2

2

主な違いは、関数内のコードを使用すると、main関数inst=0内の変数がmainnullに設定されることです。のコードを使用するとDeleteMyInstance、この行inst=0はローカル変数DeleteMyInstanceをnullに設定するだけです(それ以降は使用されないため、無駄になります。さらに警告を有効にすると、コンパイラがそれについて言及する可能性があります)。内の同じ名前の完全に別個の変数には影響しませんmain

だから、あなたのコード

DeleteMyClassInstance(inst1);
inst1->ControlPanel->Control1();

すでに削除されているオブジェクトを使用しようとしたため、動作は未定義です。UBは、何でも起こり得ることを意味します。関数がまたはデータメンバーControl1を使用しないため、実装でnull(または無効な)ポインタで呼び出された場合でも関数が「動作」することが原因であると思われる場合。thisしかし、その実装の詳細は信頼されるべきではありません。

コードが悪いC++スタイルを示していることに注意してください(まだ行っていない場合)。クラスが所有するオブジェクトを削除するための特別な関数を記述しないでください。これがデストラクタの目的です。また、デストラクタ内のオブジェクトを明示的に削除する必要はありません。これがスマートポインタの目的です。また、不要な場合は動的割り当てを使用しないでください。これが自動変数とデータメンバーの目的です。舞台裏で行われていることを学習するために、このコードを一度正しく取得してください。ただし、できるだけ早く適切に実行することを目的としています。

于 2013-03-25T09:51:55.997 に答える
1

DeleteMyClassInstance関数をに変更します。

void DeleteMyClassInstance(MyClass **inst)
{
  delete (*inst)->ControlPanel;
  (*inst)->ControlPanel = 0;
  delete (*inst);
  *inst = 0;
}
于 2013-03-25T09:50:53.007 に答える