删除以前删除的内存

Deleting memory when it was deleted before

本文关键字:删除 内存      更新时间:2023-10-16

我有一个小型C++程序,在其中我创建了一个Person类的两个对象。此类具有用于数据的char *m_szFirstNamechar *m_szLastName

然后,我将一个对象分配给另一个对象,使两个对象的数据成员指向同一位置
在析构函数中,我删除为第一个对象分配的内存,并为指针分配NULL值。像这样的东西。

if (m_szFirstName!= NULL)
{
    delete [] m_szFirstName;
    m_szFirstName = NULL;
}

然后,当我去删除第二个对象的内存时,对NULL的检查不起作用,当我删除内存时,我会崩溃。从调试器中,它显示我的指针不是NULL。它具有0xfeee

我知道以前已经删除了内存,不应该删除。然而,我不知道如何检查是否应该删除内存。

崩溃原因:
您应该遵循三规则来避免悬挂指针的问题。

如果您需要自己显式声明析构函数、复制构造函数或复制赋值运算符,则可能需要显式声明这三个运算符。

在您的情况下,您没有定义复制赋值运算符,从而导致指针的浅层复制。

建议的解决方案:

如果您可以使用std::string而不是char *,只需简单地使用std::string,它就比任何愚蠢的指针内容都具有首要的偏好
使用std::string可以避免所有时髦的指针。

如果你读不下去,下面的建议通常适用于任何类指针成员。

请注意,这里的理想解决方案是根本不使用原始指针。无论何时使用原始指针,都必须手动管理它们获取的资源,手动管理资源总是很困难且容易出错。因此,我们有责任避免这种情况

为此,您应该使用智能指针,它将隐式管理指针的动态内存。使用智能指针将确保动态存储器在使用后被隐式释放&你不必手动管理它。

您所拥有的场景正是在C++中您应该依赖RAII而不是手动资源管理的原因;在您的情况下,使用智能指针是一种可行的方法。

注意事项:
请注意,我克制自己,不建议使用哪个智能指针,因为选择取决于所涉及元素的所有权寿命,这从问题中提供的数据中并不清楚。因此,我建议阅读,

何时使用哪种指针?

选择要使用的智能指针。

使用

if (m_szFirstName!= NULL)
{ 
  delete [] m_szFirstName;
  m_szFirstName = NULL;
}

仅将m_szFirstName设置为指向NULL,而不是m_szLastName。这意味着你必须有一些方法来跟踪它们指向同一位置的事实。他们指向同一地点有什么原因吗?你能复制这个名字而不是把指针指向同一个地方吗?

如果你需要两个指针来共享相同的数据,我会看看std::tr1::shared_ptr,它将通过跟踪引用的数量并在引用数量达到0时删除来为你解决这个问题。

如果(m_szFirstName==m_szLastName),则不要再次删除它。但这会导致内存泄漏(当您将一个指针分配给另一个指针时)。

当有两个指针指向同一位置时(在将第一个指针分配给第二个之后),就有两个指向同一地址的指针。删除一个会释放它们所指向的内存。但将其中一个指针设置为NULL不会改变另一个指针。例如,如果有两个整数,也会发生同样的情况。

int a = 3;
int b = a;

现在,如果你运行

a = 0;

CCD_ 13的值不变。同样,当你改变第一个指针时,你的第二个指针不会改变(但当你改变其中一个指针指向的内存时,你也可以通过另一个指针看到效果)。

您的问题是一个经典的C/C++问题,即所谓的"挂起指针"问题。取消对悬挂指针的引用导致了崩溃。问题是关于引用计数。一旦将相同的内存分配给第二个指针,则引用计数应为2。因此,如果删除一个指针,则引用计数应变为1,并且除非计数为0,否则不应解除分配或释放内存。在0时可以进行垃圾收集。

现在,上面有很好的答案可以解决你的问题。由于您使用的是C++,所以您可以使用类似auto_ptr(OR shared_ptr)的东西。它们提供了我上面提到的,引用计数的东西,即使你不必担心删除或释放你的对象,这些类也会很好。他们在被称为RAII模式的simething上工作,当堆栈上的对象超出范围时,析构函数会被自动神奇地调用。

删除对象后,只需停止将指针设置为NULL即可。正如你所看到的,这只会导致疼痛。您不能认为因为指针不是NULL,所以它还没有被删除。

您可以使用任何合理的模式来避免这个问题。例如,Boost的shared_ptr就是一个不错的选择。