我有一个小的C ++程序,我创建了两个Person
类的对象。此类的数据为char *m_szFirstName
和char *m_szLastName
。
然后我将一个对象分配给另一个对象,导致两个对象的数据成员指向同一位置
在析构函数中,我删除了为第一个对象分配的内存,并为指针分配了NULL
值。这样的事情。
if (m_szFirstName!= NULL)
{
delete [] m_szFirstName;
m_szFirstName = NULL;
}
然后当我去删除第二个对象的内存时,检查NULL
不起作用,当我删除内存时,我遇到了崩溃。从调试器,它显示我的指针不是NULL
。它有0xfeee
。
我知道之前已经删除了内存,不应该删除。但是,我不知道如何检查是否应该删除内存。
答案 0 :(得分:4)
崩溃原因:
您应该按照 Rule of Three 来避免悬挂指针的问题。
如果您需要自己显式声明析构函数,复制构造函数或复制赋值运算符,您可能需要显式声明它们中的所有三个。
在您的情况下您没有定义复制赋值运算符,从而导致指针的浅拷贝。
建议的解决方案:
如果您可以使用std::string
代替char *
,只需使用std::string
,它首先会优先于任何类型的愚蠢指针。左右。
您可以使用std::string
来避免所有时髦的指针。
如果您无法阅读,则以下建议通常适用于任何类指针成员。
请注意,这里的理想解决方案是根本不使用原始指针。无论何时使用原始指针,您都必须手动管理它们获取的资源,因此手动管理资源总是很困难且容易出错。所以是为了避免它。
为此,您应该使用 Smart pointer 来隐式管理指针的动态内存。使用智能指针将确保在使用和放大后隐式释放动态内存;您不必手动管理它。
你所拥有的场景就是在C ++中你应该依赖 RAII 而不是手动资源管理&使用智能指针是您的理想选择。
<强>警告:强>
请注意,我限制自己建议使用哪个智能指针,因为选择取决于所涉及元素的所有权和生存期,这是从问题中提供的数据不清楚。所以我建议阅读,
Which kind of pointer do I use when?
选择要使用的智能指针。
答案 1 :(得分:1)
使用
if (m_szFirstName!= NULL)
{
delete [] m_szFirstName;
m_szFirstName = NULL;
}
您只需将m_szFirstName设置为NULL,而不是m_szLastName。这意味着您必须有一些方法来跟踪它们指向同一位置的事实。他们是否有理由指向同一地点?你可以复制名称而不是将指针指向同一个地方吗?
如果你需要两个指针来共享相同的数据,我会看看std :: tr1 :: shared_ptr,它将通过跟踪引用数量和删除数量来解决这个问题。引用达到0。
答案 2 :(得分:0)
如果(m_szFirstName == m_szLastName),请不要再删除它。 但这会给你一个内存泄漏(当你指定一个指向其他指针时)。
答案 3 :(得分:0)
如果有两个指向同一位置的指针(在将第一个指针分配给第二个指针之后),则有两个指针指向同一个地址。删除一个可以释放它们所指向的内存。但是将一个设置为NULL
不会改变另一个指针。例如,如果您有两个整数,则会发生相同的情况。
int a = 3;
int b = a;
现在如果你运行
a = 0;
b
的值不会改变。改变第一个指针时,第二个指针不会改变的方式相同(但当你改变指针指向的内存时,你也可以通过另一个指针看到效果)。
答案 4 :(得分:0)
您的问题是一个典型的C / C ++问题,被称为“悬空指针”问题。取消引用悬空指针导致崩溃。问题在于引用计数。一旦你为第二个指针分配了相同的内存,那么引用计数应该是2.所以如果你删除一个指针,引用计数应该变为1并且你的内存不应该被释放或释放,除非count为0.在0时它可以被垃圾收集
现在上面有很好的答案来解决你的问题。由于您使用的是C ++,因此您可以使用类似auto_ptr(OR shared_ptr)的内容。它们提供了我上面提到的,引用计数的东西,甚至你不必担心删除或释放你的对象,这些类会照顾。它们处理称为RAII模式的simething,当堆栈中的对象超出范围时,会自动调用析构函数。
答案 5 :(得分:0)
删除对象后,只需停止将指针设置为NULL即可。如你所见,它只会导致痛苦。你不能假设因为指针不是-NULL,所以它还没有被删除。
您可以使用任何合理的模式来避免此问题。例如,Boost的shared_ptr
是一个很好的选择。