2012-02-17 65 views
2

我有一个小型的C++程序,我创建了一个Person类的两个对象。该课程有char *m_szFirstNamechar *m_szLastName数据。当它被删除之前删除内存

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

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

然后,当我去删除第二个对象的内存,为NULL检查不工作,当我删除的记忆,我得到一个崩溃。从调试器,它显示我的指针不是NULL。它有0xfeee

我知道内存已被删除,不应删除。但是,我不知道如何检查是否应该删除内存。

+0

你能展示一些代码吗? – cnicutar 2012-02-17 07:15:38

+0

当你复制你的Person实例时,第二个对象拥有**自己的**成员。也就是说,它有自己的'm_szFirstName',它的值是从原始实例复制的。请注意,只有指针被复制,而不是指向的内存**。所以当你在删除第一个实例后将第一个实例设置为NULL时,第二个实例将保留它的值并指向“已删除”的内存。 – ereOn 2012-02-17 07:34:32

+0

代码太大,无法在此处添加。我想示范你不能将一个对象(用char *数据)分配给另一个对象,除非你拒绝赋值操作符并在其中做一个拷贝。否则,两个对象的数据将指向相同的内存。当第一个对象被删除时,第二个对象数据将有损坏的数据。 – 2012-02-19 18:10:24

回答

4

原因崩溃:
您应该遵循Rule of Three避免悬摆指针的这个问题。

如果您需要自己显式声明析构函数,复制构造函数或复制赋值运算符,则可能需要明确声明它们中的所有三个。

您的情况您没有定义复制赋值操作符,从而导致指针的浅拷贝。

建议解决方案:

如果您可以使用的std::string代替char *只是简单地使用std::string,它比任何一种愚蠢的指针的东西首先是偏好。
您可以使用std::string来避免所有时髦的指针。

如果您无法阅读,以下建议适用于任何类别指针成员。

请注意,这里的理想解决方案是根本不使用原始指针,每当您使用原始指针时,您都不得不手动管理它们获取的资源,但手动管理资源总是困难且容易出错。责任是为了避免它。

要做到这一点,你应该使用Smart pointer将管理指针implicitly.Using智能指针的动态内存将确保动态内存使用情况&后含蓄地释放您不必手动管理它。

你的情况是这个原因,在C++中,你应该依靠RAII而非人工资源管理&使用的是智能指针去了解你的情况的方式。

警告:
注意,我克制住自己从提示其中智能指针使用的,因为选择,而依赖于所有权一生所涉及的元素,这是不是从数据清楚在Question.So我会建议阅读提供,

Which kind of pointer do I use when?

,使您的智能指针的选择使用。

+0

注意:使用RAII时,您应该遵循[二大法则] http://www.artima.com/cppsource/bigtwo.html – Arafangion 2012-02-17 07:32:18

+0

好的答案。然而,在他的情况下,很可能他真正需要的是一个“std :: string”来存储它的名字和姓氏。 – ereOn 2012-02-17 07:37:06

+0

@ereOn:*可能*是,*当然*我们不知道,不管怎样,对于任何指针成员来说,答案总的来说都很好。当然,如果一个人可以使用'std :: string',它首先会优先于任何一种愚蠢的指针。我看到很多Assignments相关的Q的推动解决方案不使用'std :: string'这是很愚蠢的,我假设这些情况之一。反正我会编辑答案来反映这一点。谢谢。 – 2012-02-17 07:39:15

0

不要再删除它,如果(m_szFirstName == m_szLastName)。 但是,这会给你一个内存泄漏(当你分配一个指针到其他)。

1

随着

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

你只设置m_szFirstName指向NULL,不m_szLastName。这意味着你必须有一些方法来跟踪他们指向同一位置的事实。他们指向同一地点是否有理由?你可以复制这个名字,而不是将指针指向同一个地方吗?

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

0

当您有两个指向同一位置的指针(在您将第一个指向第二个指针后)时,您有两个指针指向相同的地址。删除一个可以释放它们两个指向的内存。但设置一个到NULL不会改变另一个指针。例如,如果您有两个整数,则会发生同样的情况。

int a = 3; 
int b = a; 

现在,如果你运行

a = 0; 

b值不会改变。第二个指针在改变第一个指针时不会改变(但是当您更改指针指向的内存时,您也可以通过另一个指针查看效果)。

0

您的问题是一个经典的C/C++问题,称为“悬挂指针”问题。解引用悬挂指针导致崩溃。问题在于引用计数。一旦将相同的内存分配给第二个指针,那么引用计数应该是2.因此,如果删除一个指针,引用计数应该变为1,并且除非count为0,否则不应该释放或释放内存。在0时,它可以被垃圾收集。

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

0

只要在删除对象时将指针设置为NULL即可。正如你所看到的,它只会导致疼痛。你不能假设,因为指针不是NULL,它还没有被删除。

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

+0

将指针设置为nullptr或NULL是删除操作后应该做的事情,这样如果再次删除相同的指针,则不会发生任何情况。就我而言,由于一些愚蠢的原因,它崩溃了。无论如何谢谢你的建议。 – 2012-02-23 22:44:32

+0

@SaleemYusuf如你所见,如果你再次删除同一个指针,它不会阻止你导致崩溃。它所做的只是让你认为如果一个指针变量保存一个非NULL的值,这意味着访问是安全的,这是**不是** true。所以这是一个非常不好的习惯。而不是将指针设置为NULL,只是不要访问它。 (或者,更好的是,使用一个合理的指针类。) – 2012-02-23 22:48:02