C/C++字符串内存泄漏?

8

我在我的应用程序中使用STL string,最近在测试内存泄漏时发现了一个问题,我注意到很多字符串在程序结束时没有被正确地释放。

我使用以下代码(并非逐字翻译)测试其中一个字符串:

const string* cppString = &obj->objString;
const char* cString = cppString->c_str();
delete obj;

在此之后,我设置了断点并注意到,虽然cppString指向的string已经不存在了,但cString仍然指向一个C风格的字符串,这个字符串显然无法在最后被释放。
我是否对C/C++字符串的工作方式有所遗漏?如何使C字符串表示也被释放?
我的obj类是Dialog类型,继承自Popup。我认为可能是这个原因,因为当我删除obj时,我将其视为Popup*处理,但我在一个小的独立程序中尝试过,按父类删除可以正确地删除子成员变量(当然这是有道理的)。
我在Visual Studio中使用了内存泄漏跟踪功能,它显示最终泄漏的字符串是在我创建Dialog并将objString设置为传递给构造函数的字符串时创建的。

抱歉,我之前的评论由于读取操作符优先级错误而出现了错误。我认为您需要展示更多的代码。如果没有看到obj的定义以及它的分配方式,很难推测obj->objString是否会被正确释放。 - Steve Jessop
这里看起来有点混乱,所以我会在原始帖子中更新我的评论。 - Jengerer
1
Popup有虚析构函数吗? - Adam Rosenfield
@Adam:太棒了!正如我在我的原始帖子中编辑的那样,我怀疑它没有进行正确的析构函数调用,但当我尝试将析构函数设置为虚函数时,我可能做错了什么。现在我已经尝试过了,它完美地工作了。我会接受你的回答;你介意在你的回答中提到这一点,以便能够帮助其他可能遇到此问题的人吗? - Jengerer
2个回答

9
您所看到的是未定义行为,实际上不是内存泄漏。C字符串的内存已经被释放(至少在您看来是这样),但其中的数据仍然可以访问。释放内存时,通常不会擦除内存,因此只要内存没有被后续分配重复使用,其中的数据通常仍然存在。
释放内存后读取数据是未定义的行为:您可能得到释放之前的数据,可能得到垃圾数据,可能使程序崩溃,或者甚至可能擦除硬盘(但这种情况不太可能发生)。
只要std::string对象被正确地释放,用于其C字符串表示的任何内存也将被释放。您不需要担心这个问题。
编辑:实际上,结果显示您的对象没有被完全销毁,因为父类Popup没有虚析构函数。因此,子类Dialog的析构函数未被调用,因此未调用std::string实例的析构函数。

这样做很有道理,但我使用了Visual Studio的内存泄漏检测过程(基本上跟踪所有的mallocfree调用),当我在程序结束时转储内存泄漏信息时,该字符串与类似位置的字符串一起显示为未正确释放。 - Jengerer

3
问题很可能不在于std::string,而在于obj(无论它是什么类型)。请注意,您删除的是obj,而不是cppString。我猜想obj没有将objString存储在智能指针类中,也没有在其析构函数中删除objString,因此导致了内存泄漏。

objString 是一个普通字符串,不是指针,因此应该由默认析构函数自动删除,对吗? - Jengerer
@Jengerer,你将objString分配给了类型为“const string*”,而不是“const string”类型,因此它必须是指针类型,除非你与我们分享了不同的代码。 - Michael Aaron Safyan
我的意思是,在对象类中,objString 是一个 string 类型而不是指针。当我将它分配给 const string* 时,我使用了 &obj->objString,所以我使用了 & 运算符来获取地址。 - Jengerer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接