在析构函数中将类成员设置为null

时间:2014-03-20 02:46:43

标签: c++ destructor

this页面中有一段代码:

class MyString
{
    private:
    char *m_pchString;
    int m_nLength;

public:
    MyString(const char *pchString="")
    {
        // Find the length of the string
        // Plus one character for a terminator
        m_nLength = strlen(pchString) + 1;

        // Allocate a buffer equal to this length
        m_pchString = new char[m_nLength];

        // Copy the parameter into our internal buffer
        strncpy(m_pchString, pchString, m_nLength);

        // Make sure the string is terminated
        m_pchString[m_nLength-1] = '\0';
    }

    ~MyString() // destructor
    {
        // We need to deallocate our buffer
        delete[] m_pchString;

        // Set m_pchString to null just in case
        m_pchString = 0;
    }

    char* GetString() { return m_pchString; }
    int GetLength() { return m_nLength; }
};

在析构函数中,编写器将 m_pchString 设置为null,以防万一。如果我们不将它设置为null,会发生什么?我们已经释放了指定的内存,类成员将在退出时被杀死。这样做有什么好处?

4 个答案:

答案 0 :(得分:1)

如果指针设置为NULL,则可能实际上隐藏了使用已删除对象的错误,例如通过指向对象的悬空指针,因为错误代码可能会检查NULL在尝试使用数据之前。在一种可能被认为是安全的思维方式中。行为,但发生的事情是你实际上隐藏了已经发生的缺陷。

请记住,隐藏错误与修复错误不同。在重新分配内存后,实际上可以再次使用该悬空指针,并将有效指针放在同一个内存位置。此时,有缺陷的代码将开始使用新的有效指针,但原因不正确。

因此,实际上将指针设置为可能导致崩溃的事情可能会更好,如果它使用不当:

m_pchString = (char*) 0xdeaddead;

现在,如果某些东西试图使用已删除对象的成员指针(这是一个错误),它将快速失败,并且将捕获该错误而不是隐藏错误。

在调试版本中使用MSVC(以及可能的其他工具链),您已经可以通过调试堆获得该行为。 MSVC调试堆填充通过free()operator delete释放的内存,值为0xdd:https://stackoverflow.com/a/370362/12711

答案 1 :(得分:1)

除了Michael Burr提供的答案之外,在Tietbohl提供的链接的帮助下,this也是一个很好的答案。我引用它:

  

它可以帮助捕获许多对自由内存的引用(假设你的平台在空指针的deref上出错)。

     

它不会捕获所有对自由内存的引用,例如,如果你有一个指针的副本。但有些人比没有人好。

     

它会掩盖双重删除,但我发现这些远比访问已释放的内存少得多。

     

在许多情况下,编译器会优化它。因此,不必要的论点并没有说服我。

     

如果你已经在使用RAII,那么你的代码中就不会有很多删除事件,因此额外分配导致混乱的论点并不能说服我。

     

在调试时,通常很方便查看空值而不是过时的指针。

     

如果这仍然困扰你,请使用智能指针或参考。

答案 2 :(得分:0)

如果不将其设置为NULL,则没有任何害处。删除对象后,您无论如何都不应该访问其成员数据。

答案 3 :(得分:0)

当你已经删除了内存位置时,析构函数只是一个很好的编程实践,只有在出现任何隐藏错误的情况下才有帮助。