哪个版本的safe_delete更好?

时间:2009-02-12 11:29:54

标签: c++ pointers c-preprocessor

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

OR

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

或任何其他更好的方式

9 个答案:

答案 0 :(得分:18)

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

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

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

但是,如果必须这样做,请使用模板 - 宏总是有可能在其他名称上进行打击。

答案 1 :(得分:7)

删除a;

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

引自iso 14882:

    5.3.5 Delete [expr.delete]

    2   [...] In either alternative, if the value of the operand of delete is the 
        null pointer the operation has no effect. [...]

此致,Bodo

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

答案 2 :(得分:6)

很明显这个功能,原因很简单。宏多次计算其参数。这可能有邪恶的副作用。该函数也可以作用域。没有比这更好的了:))

答案 3 :(得分:5)

通常,首选内联函数而不是宏,因为宏不考虑范围,并且在预处理期间可能与某些符号冲突,导致非常奇怪的编译错误。

当然,有时模板和功能不会,但在这种情况并非如此。

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

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

答案 4 :(得分:2)

您不需要使用delete测试无效,它等同于无操作。 (a) = NULL让我抬起眉毛。第二种选择更好。

但是,如果您有选择,则应使用已经为您执行此操作的智能指针,例如std::auto_ptrtr1::shared_ptr

答案 5 :(得分:2)

我认为

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

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

答案 6 :(得分:1)

SAFE_DELETE的使用似乎是C程序员用C ++编写内置内存管理的方法。我的问题是:C ++是否允许这种方法在已正确封装为Private的指针上使用SAFE_DELETE?这个宏只能用于声明为Public的指针吗? OOP BAD !!

答案 7 :(得分:0)

正如上面提到的那样,第二个是更好的一个,而不是一个有潜在意外副作用的宏,没有对NULL的不必要的检查(尽管我怀疑你这样做是一种类型检查),但是,他们都没有承诺任何安全。如果你确实使用了类似tr1 :: smart_ptr的东西,请确保你阅读它们上的文档,并确保它具有适合你的任务的语义。我最近不得不追捕和清理一个巨大的内存泄漏,因为一个同事将smart_ptrs放入一个带有循环链接的数据结构:)(他应该使用weak_ptrs作为反向引用)

答案 8 :(得分: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和智能指针。