C++ 在析构函数中将类成员设置为null
在第页中有一段代码:C++ 在析构函数中将类成员设置为null,c++,destructor,C++,Destructor,在第页中有一段代码: 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 = strle
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; }
};
在析构函数中,编写器将mu pchString设置为null,并表示以防万一。如果不将其设置为null,会发生什么?我们已经释放了指定的内存,类成员将在退出时被杀死。这样做的好处是什么?如果不将其设置为NULL,则没有什么坏处。删除对象后,无论如何都不应该访问其成员数据。如果指针设置为
NULL
,则使用已删除对象的错误(例如通过指向该对象的悬空指针)实际上可能会被隐藏,因为错误代码可能会在尝试使用数据之前检查NULL
。在一种思维方式中,可能会考虑“安全”的行为,但发生的是,你实际上隐藏了已经发生的缺陷。
请记住,隐藏bug与修复bug是不同的。在重新分配内存后,该悬空指针可能会再次使用,并将有效指针放在同一内存位置。此时,错误代码将开始使用新的有效指针,但原因不正确
因此,实际上最好将指针设置为如果使用不当会导致崩溃的对象:
m_pchString = (char*) 0xdeaddead;
现在,如果某个东西试图使用已删除对象(这是一个bug)的成员指针,它将很快失败,bug将被捕获而不是隐藏
在使用MSVC(可能还有其他工具链)的调试构建中,您已经在调试堆中获得了这种行为。MSVC调试堆将通过
free()
或运算符delete
释放的内存填充为0xdd:当您已经删除了内存位置时,析构函数只是一种很好的编程实践,它只会在出现任何隐藏错误时提供帮助。在Michael Burr提供的答案旁边,在Tietbohl提供的链接的帮助下,也可以是一个很好的答案。我引述:
它可以帮助捕获对空闲内存的许多引用(假设您的平台在一个空指针上出现错误)
例如,如果您有指针的副本,它将不会捕获对空闲内存的所有引用。但有总比没有好
它会屏蔽双重删除,但我发现这种情况远不如访问已经释放的内存常见
在许多情况下,编译器会对其进行优化。所以说这是不必要的论点说服不了我
如果您已经在使用RAII,那么代码中的删除就不多了,因此额外的赋值会导致混乱的说法无法说服我
调试时,通常可以方便地看到空值,而不是过时的指针
如果这仍然困扰您,请使用智能指针或引用
这段代码实际上没有效果,优化编译器可以完全删除它。