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** 代替

“Child”和“Child*”不是同一类型。

于 2009-04-10T09:20:36.680 回答
3

您需要做的是使所有指向您刚刚删除的对象的指针无效。指针的思想是有不止一个指针存储同一个对象的地址。如果不是,则几乎没有理由使用裸指针,因此您尝试捕获的模式不是很有用 - 但您远不是第一个尝试这个的人。正如其他答案所提到的,处理指针的唯一方法是仔细控制对它们的访问。

你的问题的标题是绝对正确的!这是有充分理由的。指针标识存储特定类型对象的位置。指向指针的指针使您能够更改指针指向的对象。

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

你的Child类派生自Parent,我的类也是如此OtherChild。假设编译器允许您这样做:

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

您希望它可以工作,但如果它可以工作,那么我们现在将有一个Child指针c,它实际上指向OtherChild. 谁说这两种类型可以兼容?

List<Parent>同样,这是一个非常常见的误解——它在这里反复出现在其他语言中,尤其是List<Child>在 C# 中。

于 2009-04-10T09:52:40.287 回答
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 回答
2

如果您的问题是处理内存和资源,最好的建议是完全忘记您的方法并使用智能指针。std::auto_ptrboost::shared_ptr将是一个起点。

如果您使用智能指针保存所有堆分配的资源,您的代码将更加健壮。

于 2009-04-10T09:35:24.070 回答
1

你可以从《C++ 常识》Item 8. Pointers to Pointers 一书中找到一些有用的信息。

于 2009-04-10T08:16:08.363 回答
0

可能是我找到的最简单的解决方案:

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

就叫这个:

   __REMOVE_OBJ(pPObj);
   __REMOVE_OBJ(pCObj);

但是我自己不是很喜欢...

于 2009-04-10T11:14:51.180 回答
0

从关于make shared_ptr 的讨论不使用删除

共享指针将确保您在应该清理的时候进行清理,并且您不会访问被破坏的东西。此外,您可以专门化并提供另一种销毁方法。

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