C++ 如何安全地删除多个指针

C++ 如何安全地删除多个指针,c++,pointers,memory,delete-operator,C++,Pointers,Memory,Delete Operator,我有一些代码,它使用了很多指向同一地址的指针。 给出一个等效的简单示例: int *p = new int(1); int *q = p; int *r = q; delete r; r = NULL; // ok // delete q; q = NULL; // NOT ok // delete p; p = NULL; // NOT ok 如何在不进行多次删除的情况下安全地删除它? 如果我有很多对象的指针都指向同一个地址,这就特别困难。您的工具是boost库的共享的。请查看文档: 例

我有一些代码,它使用了很多指向同一地址的指针。 给出一个等效的简单示例:

int *p =  new int(1);
int *q = p;
int *r = q;

delete r; r = NULL; // ok
// delete q; q = NULL; // NOT ok
// delete p; p = NULL; // NOT ok
如何在不进行多次删除的情况下安全地删除它?
如果我有很多对象的指针都指向同一个地址,这就特别困难。

您的工具是
boost
库的
共享的。请查看文档:

例如:

void func() {
  boost::shared_ptr<int> p(new int(10));
  boost::shared_ptr<int> q(p);
  boost::shared_ptr<int> r(q);

  // will be destructed correctly when they go out of scope.
}
void func(){
boost::shared_ptr p(新int(10));
boost::shared_ptr q(p);
boost::共享的ptr(q);
//当它们超出范围时将被正确销毁。
}
现代的答案是使用智能指针,不进行任何手动删除

boost::shared_ptr<int> p(new int(1));
boost::shared_ptr<int> q = p;
boost::shared_ptr<int> r = q;
boost::shared_ptr p(新int(1));
boost::shared_ptr q=p;
boost::shared_ptr r r=q;

故事结束了

答案是,在不使用托管指针的情况下,您应该知道是否根据指针的分配位置删除指针

您的示例有点做作,但在实际应用程序中,负责分配内存的对象将负责销毁内存。接收已经初始化的指针并将其存储一段时间的方法和函数不会删除这些指针;这个责任在于最初分配内存的任何对象


请记住,对
new
的调用应该与对
delete
的调用相平衡。每次分配内存时,您都知道必须编写平衡代码(通常是析构函数)来释放内存。

在一些非常罕见的情况下,您可能无法使用智能指针(可能是处理旧代码),但也无法使用简单的“所有权”方案

假设您有一个
std::vector
和一些
任意*
指针指向同一个对象。安全清理包括确保不删除两次相同的指针,因此在执行时构建一个
std::set
,只删除集合中不存在的指针。删除所有指向的对象后,也可以安全地删除这两个容器

insert
的返回值可用于确定插入的项目是否为新项目。我还没有测试以下内容(或使用std::set有一段时间了),但我认为以下内容是正确的

if (myset.insert (pointervalue).second)
{
  //  Value was successfully inserted as a new item
  delete pointervalue;
}

当然,您不应该设计项目,这样做是必要的,但如果您无法避免这种情况,那么处理这种情况也不太困难。

您面临的问题是程序中的所有权语义不明确。从设计的角度来看,尝试在每个步骤确定谁是对象的所有者。在许多情况下,这意味着无论是谁创建了对象,都必须在以后将其删除,但在其他情况下,所有权可以转移甚至共享


一旦你知道谁拥有内存,然后回到代码并实现它。如果一个对象是另一个对象的唯一负责人,则该对象应通过单个所有权智能指针(
std::auto_ptr
/
unique_ptr
)或甚至原始指针(尽量避免这种情况,因为它是常见的错误源)来持有该对象,并手动管理内存。然后将引用或指针传递给其他对象。所有权转移时,使用智能指针工具将对象移交给新所有者。如果所有权是真正共享的(分配的对象没有明确的所有者),那么您可以使用
shared\u ptr
,让智能指针处理内存管理)。

为什么要任意删除指针?每个动态分配的对象由一个所有者在一个位置分配。而且应该由一个所有者负责确保再次删除该对象

在某些情况下,您可能希望将所有权转移到另一个对象或组件,在这种情况下,删除的责任也会发生变化

有时,您只想忘记所有权而使用共享所有权:使用对象的每个人都共享ownersip,并且只要至少存在一个用户,就不应该删除该对象

然后使用
shared\u ptr


简而言之,使用RAII。不要尝试手动删除对象。

无法知道指针引用的内存是否已被删除,就像您的情况一样。
如果您不能使用带有智能指针的库,该库会进行引用计数,并且您不能实现自己的引用计数模式(如果确实需要执行您在文章中描述的操作),请尝试在指针上调用realloc。
我在其他帖子中读到,根据实现的不同,对realloc的调用可能不会崩溃,但会返回一个空指针。在这种情况下,您知道该指针引用的内存已被释放。

如果这是一个脏的解决方案,它将不可移植,但如果您没有其他选择,请尝试它。更糟糕的当然是应用程序崩溃:)

我想说的是,有时,智能指针实际上会降低应用程序的速度,但不会降低很多。我要做的是创建一个方法,如下所示:

void safeDelete(void **ptr)
{
  if(*ptr != NULL)
  {
     delete ptr;
     *ptr = NULL;
  }
}

我不确定我是否100%正确,但您要做的是将指针传递到这个方法中,该方法接受指针的指针,检查以确保它指向的指针未设置为NULL,然后删除对象,然后将地址设置为0或NULL。纠正我,如果这不是一个很好的方法,我也是新手,有人告诉我这是一个很好的检查方法,不会变得复杂

这不管用吗?标准中指定了delete null,因此它是允许的,应该可以工作。好的,这不是最好的编码方式…@Mario:Deleting NULL被指定为NO-OP,但调用它会带来一些开销。问题是q和p不会为NULL,所以会有双重删除。@Mario当您删除
q
p
时,您并没有在NULL上调用
delete
;您正在对旧a调用delete