5
#define SAFE_DELETE(a) if( (a) != NULL ) delete (a); (a) = NULL;

或者

template<typename T> void safe_delete(T*& a) {
  delete a;
  a = NULL;
}

或任何其他更好的方式

4

9 回答 9

17

我不会说,因为两者都会给你一种虚假的安全感。例如,假设您有一个函数:

void Func( SomePtr * p ) {
  // stuff
  SafeDelete( p );
}

您将 p 设置为 NULL,但函数外部的 p 副本不受影响。

但是,如果您必须这样做,请使用模板 - 宏总是有可能超越其他名称。

于 2009-02-12T11:39:02.497 回答
7

删除一个;

ISO C++ 规定,对 NULL 指针的删除不做任何事情。

引自 ISO 14882:

    5.3.5 删除[expr.delete]

    2 [...] 在任一备选方案中,如果 delete 的操作数的值是
        空指针操作无效。[...]

问候, 博多

/edit:我没有注意到 a=NULL; 在原来的帖子中,所以新版本:删除一个;一个=空;但是,已经指出了设置 a=NULL 的问题(错误的安全感)。

于 2009-02-12T11:35:40.727 回答
7

很明显的功能,原因很简单。宏多次评估其参数。这可能会产生不良的副作用。该功能也可以限定范围。没有比这更好的了:)

于 2009-02-12T11:41:00.510 回答
5

一般来说,比起宏,更喜欢内联函数,因为宏不考虑作用域,并且在预处理过程中可能会与某些符号冲突,从而导致非常奇怪的编译错误。

当然,有时模板和函数是不行的,但这里不是这样。

此外,不需要更好的安全删除,因为您可以使用智能指针,因此不需要记住在客户端代码中使用此方法,而是将其封装。

编辑)正如其他人指出的那样,安全删除并不安全,即使有人没有忘记使用它,它仍然可能达不到预期的效果。所以它实际上完全没有价值,因为正确使用 safe_delete 需要更多的思考,而不仅仅是自己设置为 0。

于 2009-02-12T11:35:29.150 回答
2

您不需要使用 来测试无效性delete,它相当于无操作。(a) = NULL让我挑眉。第二种选择更好。

但是,如果您有选择,您应该使用智能指针,例如std::auto_ptror tr1::shared_ptr,它已经为您执行此操作。

于 2009-02-12T11:36:42.720 回答
2

我认为

#define SAFE_DELETE(pPtr) { delete pPtr; pPtr = NULL }更好

  1. 如果 pPtr 为 NULL,则可以调用 delete。因此,如果不需要检查。
  2. 如果您调用 SAFE_DELETE(ptr+i),则会导致编译错误。
  3. 模板定义将为每种数据类型创建函数的多个实例。在我看来,在这种情况下,这些多重定义不会增加任何价值。
  4. 此外,使用模板函数定义,您会产生函数调用的开销。
于 2009-02-12T12:24:01.110 回答
1

SAFE_DELETE 的使用似乎是 C 程序员在 C++ 中控制内置内存管理的一种方法。我的问题是:C++ 是否允许在已正确封装为 Private 的指针上使用 SAFE_DELETE 的这种方法?此宏是否仅适用于声明为 Public 的指针?糟糕!

于 2009-03-20T16:30:34.777 回答
0

如上所述,第二个更好,不是具有潜在意外副作用的宏,没有对 NULL 的不必要检查(尽管我怀疑您是在进行类型检查)等等。但是两者都没有承诺任何安全性。如果您确实使用了 tr1::smart_ptr 之类的东西,请确保您阅读了它们的文档并确保它具有适合您任务的语义。由于同事将 smart_ptrs 放入具有循环链接的数据结构中,我最近不得不寻找并清理巨大的内存泄漏:)(他应该使用weak_ptrs 进行反向引用)

于 2009-02-12T12:56:22.873 回答
0

我更喜欢这个版本:

~scoped_ptr() {
    delete this->ptr_; //this-> for emphasis, ptr_ is owned by this
}

在删除指针后将指针设置为 null 毫无意义,因为您使用指针的唯一原因是允许一次在多个位置引用一个对象。即使程序某一部分的指针为 0,也可能有其他部分未设置为 0。

此外,safe_delete 宏/函数模板很难正确使用,因为如果在给定指针的 new 和 delete 之间存在可能抛出的代码,则只有两个地方可以使用它。

1) 在重新抛出异常的 catch (...) 块内,并在不抛出的路径的 catch (...) 块旁边复制。(在每个可能允许指针超出范围的中断、返回、继续等旁边也重复)

2) 在拥有指针的对象的析构函数中(除非在 new 和 delete 之间没有可以抛出的代码)。

即使在您编写代码时没有可能抛出的代码,这也可能在未来发生变化(只需有人出现并在第一个代码之后添加另一个新代码)。最好以即使面对异常也保持正确的方式编写代码。

选项 1 产生了如此多的代码重复并且很容易出错,以至于我什至怀疑将其称为选项。

选项 2 使 safe_delete 变得多余,因为您设置为 0 的 ptr_ 将超出下一行的范围。

总之——不要使用 safe_delete,因为它根本不安全(正确使用非常困难,即使使用正确也会导致冗余代码)。使用 SBRM 和智能指针。

于 2011-06-12T03:28:53.327 回答