2

ポインターをきれいにする適切な方法を探しています。ここにコード例があります:

class Parent {
   protected:
      int m_Var;
   public:
      Parent() : m_Var(0) {}
      virtual ~Parent() {}
      void PubFunc();
};

class Child : public Parent {
   protected:
      bool m_Bool;
   public:
      Child() : m_Bool(false) {}
      virtual ~Child() {}
      void ChildFunc();
};

void RemoveObj(Parent **ppObj)
{
   *ppObj->PubFunc();
   delete *ppObj;
   ppObj = NULL;
}

int main()
{
   Parent* pPObj = NULL;
   Child*  pCObj = NULL;
   pPObj = new Parent();
   pCObj = new Child();

   RemoveObj(&pPObj);
   RemoveObj(&pCObj); // This is line 33
   return 1;
}

しかし、コンパイラはエラーを出します:

classes.cpp:33: error: invalid conversion from ‘Child**’ to ‘Parent**’
classes.cpp:33: error:   initializing argument 1 of ‘void RemoveObj(Parent**)’
4

8 に答える 8

12

メモリを正しく処理する方法はたくさんあります。

あなたの例に近いものは次のとおりです。

template <typename T>
RemoveObj(T **p)
{
    if (p == NULL) return;
    delete *p;
    *p = NULL;
}

さらに、代わりに std::auto_ptr を使用することもできます。次のようになります。

int main()
{
   std::auto_ptr<Parent*> pPObj(new Parent);
   std::auto_ptr<Child*> pCObj(new Child);
   // no deletes needed anymore
于 2009-04-10T07:49:05.823 に答える
3

簡単に言えば:

ChildはParentのサブクラスであるため、Child*をParent*に置き換えることができます。

しかし

Child*はParent*のサブクラスではないため、Child**をParent**に置き換えることはできません。

「子」と「子*」は同じ種類ではありません。

于 2009-04-10T09:20:36.680 に答える
3

必要なことは、削除したばかりのオブジェクトへのすべてのポインターを無効にすることです。ポインターの考え方は、同じオブジェクトのアドレスを格納する複数のポインターが存在することです。そうでない場合、そのままのポインタを使用する理由はほとんどないため、キャプチャしようとしているパターンはあまり役に立ちませんが、これを試す最初の人からはかけ離れています。他の回答が述べたように、ポインターを処理する唯一の方法は、ポインターへのアクセスを慎重に制御することです。

あなたの質問のタイトルは絶対に正しいです!それには正当な理由があります。ポインターは、特定の型のオブジェクトを格納する場所を識別します。ポインターへのポインターを使用すると、ポインターが指すオブジェクトを変更できます。

void Foo(Parent **pp)
{
    *pp = new OtherChild();
}

あなたのChildクラスは から派生してParentおり、私のOtherChildクラスもそうです。コンパイラーがこれを許可したとします。

Child *c = 0;
Foo(&c);

あなたはそれがうまくいくことを期待していましたが、もしそうなら、実際には のインスタンスをChild指すポインターが得られます。これらの 2 つのタイプが互換性があると誰が言いますか?cOtherChild

繰り返しますが、これは非常によくある誤解です。他の言語、特にC#に関してはList<Parent>、ここで繰り返し発生します。List<Child>

于 2009-04-10T09:52:40.287 に答える
2

問題がメモリとリソースを扱っている場合、最善のアドバイスは、アプローチを完全に忘れて、スマート ポインターを使用することです。std::auto_ptrまたはboost::shared_ptrが出発点になります。

ヒープに割り当てられたすべてのリソースをスマート ポインターで保持すると、コードがより堅牢になります。

于 2009-04-10T09:35:24.070 に答える
2

削除のラッパーは必要ありません。シンプルにしてください。

int main()
{
  Parent* pPObj = NULL;
  Child*  pCObj = NULL;
  pPObj = new Parent();
  pCObj = new Child();

  delete pPObj;
  delete pCObj; // This is line 33
  return 1;
}

また、配列型オブジェクトを削除するときに問題が発生することを覚えておいてくださいRemoveObj(常に scalar を使用しているためdelete)。別の方法はもちろん、必要であることを示すためにフラグを渡すことですdelete []。しかし、私が言ったように:キス。

于 2009-04-10T08:19:47.090 に答える
1

< C++ の一般的な知識 > 項目 8. ポインターへのポインター という本から、いくつかの有用な情報を見つけることができます。

于 2009-04-10T08:16:08.363 に答える
0

shared_ptrを使用しないようにするに関する議論から削除を使用しない

共有ポインタは、必要なときにクリーンアップし、破壊されたものにアクセスしないようにします。さらに、別の破壊方法を専門にして提供することができます。

boost::shared_ptr<T> ptr( new T, std::mem_fun_ref(&T::deleteMe) );
于 2009-04-10T13:59:18.647 に答える
0

おそらく私が見つけた最も簡単な解決策:

#define __REMOVE_OBJ(pObj) RemoveObj(pObj); pObj = NULL;

そして、これを呼び出すだけです:

   __REMOVE_OBJ(pPObj);
   __REMOVE_OBJ(pCObj);

でも自分はあんまり好きじゃない…

于 2009-04-10T11:14:51.180 に答える