我有一些代码使用大量指向同一地址的指针。给定一个等效的简单示例:
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
如何在不多次删除的情况下安全删除它?如果我有很多指针都指向同一个地址的对象,这尤其困难。
我有一些代码使用大量指向同一地址的指针。给定一个等效的简单示例:
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
如何在不多次删除的情况下安全删除它?如果我有很多指针都指向同一个地址的对象,这尤其困难。
你的工具是shared_ptr
图书馆的boost
。看看文档: http: //www.boost.org/doc/libs/1_44_0/libs/smart_ptr/shared_ptr.htm
例子:
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.
}
答案是,在不求助于托管指针的情况下,您应该知道是否根据指针的分配位置来删除它。
您的示例有点人为,但在现实世界的应用程序中,负责分配内存的对象将负责销毁它。接收已经初始化的指针并将它们存储一段时间的方法和函数不会删除这些指针;该责任在于最初分配内存的任何对象。
请记住,您的呼叫new
应该与您的呼叫平衡delete
。每次分配内存时,您都知道必须编写平衡代码(通常是析构函数)来释放该内存。
“现代”答案是使用智能指针并且不进行任何手动删除。
boost::shared_ptr<int> p(new int(1));
boost::shared_ptr<int> q = p;
boost::shared_ptr<int> r = q;
故事结局!
您面临的问题是程序中的所有权语义不清楚。从设计的角度来看,尝试在每一步确定谁是对象的所有者。在许多情况下,这意味着创建对象的人稍后必须将其删除,但在其他情况下,所有权可以转移甚至共享。
一旦你知道谁拥有内存,然后回到代码并实现它。如果一个对象是另一个对象的唯一负责人,它应该通过单一所有权智能指针(std::auto_ptr
/ unique_ptr
)甚至原始指针(尽量避免这种情况,因为它是常见的错误来源)来保存它并管理内存手动。然后将引用或指针传递给其他对象。当所有权转移时,使用智能指针工具将对象让给新所有者。如果所有权是真正共享的(分配对象没有明确的所有者),那么您可以使用shared_ptr
并让智能指针处理内存管理)。
你为什么要随意删除指针?每个动态分配的对象都由一个所有者在一个地方分配。确保对象被再次删除应该是一个所有者的责任。
在某些情况下,您可能希望将所有权转移给另一个对象或组件,在这种情况下,删除的责任也会发生变化。
有时,您只想忘记所有权并使用共享所有权:使用该对象的每个人都共享所有权,并且只要至少存在一个用户,就不应删除该对象。
然后你使用shared_ptr
.
简而言之,使用 RAII。不要尝试手动删除对象。
在一些非常罕见的情况下,您可能无法使用智能指针(可能处理旧代码),但也不能使用简单的“所有权”方案。
想象一下,你有一个std::vector<whatever*>
和一些whatever*
指针指向同一个对象。安全清理涉及确保您不会两次删除相同的内容-因此std::set<whatever*>
请随时构建,并且仅删除尚未在集合中的指针。一旦所有指向的对象都被删除,这两个容器也可以安全地删除。
from 的返回值insert
可用于确定插入的项目是否是新的。我没有测试以下(或使用 std::set 一段时间),但我认为以下是正确的......
if (myset.insert (pointervalue).second)
{
// Value was successfully inserted as a new item
delete pointervalue;
}
当然,您不应该将项目设计成有必要这样做,但是如果您无法避免这种情况,处理这种情况并不太难。
不可能知道指针引用的内存是否已被删除,就像您的情况一样。
如果您不能使用带有智能指针的库来进行引用计数,并且您不能实现自己的引用计数模式(如果确实需要执行您在帖子中描述的操作),请尝试在指针上调用 realloc。
我在其他帖子中读到,根据实现,对 realloc 的调用可能不会崩溃,但会返回一个空指针。在这种情况下,您知道该指针引用的内存已被释放。
如果这是一个肮脏的解决方案,它将无法移植,但如果您别无选择,请尝试一下。更糟糕的当然是让你的应用程序崩溃:)
我会说,有时,智能指针实际上会减慢您的应用程序的速度,尽管不会减慢很多。我要做的是创建一个方法,如下所示:
void safeDelete(void **ptr)
{
if(*ptr != NULL)
{
delete ptr;
*ptr = NULL;
}
}
我不确定我是否 100% 正确地做到了,但你所做的是将指针传递给这个方法,该方法采用指针的指针,检查以确保它指向的指针未设置为 NULL,然后删除对象,然后将地址设置为 0 或 NULL。如果这不是这样做的好方法,请纠正我,我也是新手,有人告诉我这是一种很好的检查方法,不会变得复杂。