C ++ - 为什么在删除后将对象设置为null?

时间:2013-01-19 17:05:37

标签: c++

我正在查看我在网上找到的以下链接列表代码:

void DeleteAfter(Node **head){
      if(*head==NULL){
            return;
      }else{
            Node *temp = NULL;
            temp = (*head)->next;
            (*head)->next = (*head)->next->next;
            delete temp;
            temp=NULL;
      }
}

我不熟悉C ++,所以这可能是一个糟糕的问题,但为什么temp被删除后被设置为NULL?这是必要的一步吗?

6 个答案:

答案 0 :(得分:7)

没必要。有些人养成这样做的习惯,即使没有结果。积极的编译器优化器将消除此代码,因此它实际上不会造成任何伤害。但我会写:

void DeleteAfter(Node *head) {
  if (head) {
    Node *next = head->next;
    if (next) {
      head->next = next->next;
      delete next;
    }
  }
}

注意我消除了无用的间接级别,并添加了一个检查以确保删除后的“节点”。

习惯的基本原理是,如果指针总是引用有效对象或为null,则可以依赖空检查等效于有效性检查。

出于这个原因,Ada是一种常用于安全关键系统的语言,它将指针初始化为null并定义其delete等效运算符以自动将其参数设置为null。你的C ++正在模拟这种行为。

在实践中,这门学科的价值并不是你所希望的。很长一段时间它可以防止愚蠢的错误。然而,一件好事是调试器显示指针内容是有意义的。

答案 1 :(得分:1)

删除后你不必将本地指针变量设置为NULL。如果你想重用指针,你应该将指针设置为NULL,在NULL检查之后,你可以安全地为它分配一个新地址。通常我们这样做用于指针成员变量和全局指针变量。

答案 2 :(得分:1)

如果temp是全局变量或成员变量,那么设置为NULL并不是一个坏主意。

在使用带有C代码的保守垃圾收集器后,我养成了将指针设置为NULL的习惯。没有指向未使用内存的指针是它如何找到要收集的垃圾。但在这种情况下你也应该

temp->next = NULL;

答案 3 :(得分:1)

如果稍后可能在代码中再次使用变量temp,那么最好将其设置为NULL。

通常在释放指针后将指针设置为NULL有两个原因。

1。)释放指针后,指向的地址处的内存将不再可用于您的程序。从理论上讲,现在任何其他程序都可以使用该内存,包括操作系统本身!试图释放已经释放的指针,从而指出谁知道什么可能导致巨大的问题。幸运的是,现代操作系统可以防止这种情况,但程序仍会因非法访问错误而崩溃。释放空指针OTOH绝对不会做任何事。

2。)在使用*运算符取消引用之前,应始终检查指针是否为NULL。取消引用NULL指针将导致运行时错误。取消引用指向某个任意内存的已释放指针甚至更糟。释放的指针应始终设置为NULL,以便后面的代码可以假定非空指针指向有效数据。否则无法知道指针是否仍然有效。

对于原始问题,指针变量temp在短函数中被声明为局部变量,从而再也不会使用它。在这种情况下,没有必要将其设置为NULL,因为一旦函数返回它就会超出范围。

然而,行......

(*head)->next = (*head)->next->next;
在尝试取消引用之前,

无法确保(*head)->next不为空,否则为

更好的版本将是......

int DeleteAfter(Node **head){
  Node *node_after = NULL;

  if(*head==NULL)
    return -1;

  node_after = (*head)->next;

  if(node_after == NULL)
    return -1;

  (*head)->next = node_after->next;
  delete node_after;

  return 0;
  }

现在使用该功能的人可以通过返回值检查节点删除是否成功,并且没有尝试删除不存在的节点的风险。

答案 4 :(得分:0)

没有必要,有些人(包括我)认为这是不好的做法。

将其设置为NULL的动机是,您可以在事后检查它是否已被删除,如果不是,则可以访问它。此外,这会阻止双重删除,因为NULL指针上的delete是无操作。

另一方面,它可以隐藏错误。如果删除了对象,使用它没有意义,对吧?您应该知道该对象已被删除,而不是依赖于支票。

例如

if (p != NULL) //or just if (p)
   p->doStuff()

为什么呢?你不知道它是否被删除了吗?不是清理逻辑的一部分吗?

答案 5 :(得分:0)

在您的代码示例中,没有明显的直接好处,但可以说是一个长期的维护成本优势。这个想法是,在删除试图取消引用temp的temp后,有人最终可能会添加代码。这可能只是因为没有注意到删除,或者通过移动删除后访问临时的早期行。

以下是一个例子:

int * i = new int(12);
std::cout << *i << std::endl; // output is 12.
delete i;
// i = 0; // This would cause the program to fail on the next line.
std::cout << *i << std::endl; // output is random for me.

请注意,这并不会隐藏缺陷,实际上没有将指针设置为null会在这种情况下隐藏缺陷,因为* i会返回一个随机值。

大多数人会说i = 0可能会被编译器优化,无论是对指针的赋值大多是无害的。对我来说,在专业发展的过程中,我始终保持谨慎。