是否应该在析构函数中将指向“原始”资源的指针归零?

时间:2012-01-31 17:37:54

标签: c++ destructor raii

当我在C ++类中包装“原始”资源时,在析构函数代码中我通常只是释放已分配的资源,而不关注其他步骤,如清零指针等。 e.g:

class File
{
public:
  ...

  ~File()
  {
    if (m_file != NULL)
      fclose(m_file);
  }

private:
  FILE * m_file;
};

我想知道这段代码样式是否包含潜在错误:即是否可能多次调用析构函数?在这种情况下,正确的做法是在析构函数中将清除指针以避免双重/多重破坏:

~File()
{
  if (m_file != NULL)
  {
    fclose(m_file);
    m_file = NULL; // avoid double destruction
  }
}

可以对堆分配的内存进行类似的示例:如果m_ptr是指向分配有new[]的内存的指针,那么下面的析构函数代码是否正常?

// In destructor:
delete [] m_ptr; 

还是指针也应该被清除,以避免双重破坏?

// In destructor:
delete [] m_ptr;
m_ptr = NULL; // avoid double destruction

3 个答案:

答案 0 :(得分:5)

没有。如果你有Close()函数之类的东西很有用:

void Close()
{
    if (m_file != NULL)
    {
        fclose(m_file);
        m_file = NULL;
    }
}
~File()
{
    Close();
}

这样,Close()函数是幂等的(您可以根据需要多次调用它),并且在析构函数中避免一次额外的测试。

但是由于C ++中的析构函数只能被调用一次,所以为指针指定NULL是没有意义的。

当然,除非出于调试目的,否则,特别是如果您怀疑是双重删除。

答案 1 :(得分:2)

如果多次调用析构函数,则您已经有未定义的行为。这也不会影响可能具有指向资源本身的指针的客户端,因此这不会阻止双重删除。 unique_ptrscoped_ptr对我来说似乎是更好的解决方案。

答案 2 :(得分:2)

在一个有缺陷的应用程序中(例如,不正确地使用std :: unique_ptr<>可能导致两个std :: unique_ptr<>持有相同的原始指针),你最终可能会被双重删除,因为第二个超出范围。

我们关心这些不良案例 - 否则,讨论在析构函数中设置指向nullptr的指针有什么意义?无论如何它都会消失!

因此,在这个例子中,至少,在单元测试期间让程序在一个调试器中出现seg-fault会更好,因此你可以追踪问题的真正原因

因此,一般来说,我发现设置指向nullptr的指针对内存管理特别有用。

您可以这样做,但更强大的选择是进行单元测试并明智地使用内存检查器,例如valgrind。< / em>的

毕竟,由于存在一些内存错误,你的程序似乎可以运行很多次,直到它意外崩溃 - 使用内存检查器进行质量保证更加安全,特别是当程序变大时,内存错误变得更加容易不太明显