Will this C++ code cause a memory leak (casting array new)我一直在研究一些使用可变长度结构(TAPI)的遗留C代码,其中结构大小将取决于可变长度字符串。这些结构是通过强制转换数组
以后,使用
数组 从技术上讲,我相信这可能会导致分配器不匹配,但实际上我不知道有哪个编译器无法在此示例中执行正确的操作。 更重要的是,如果 当然,如果您知道pStruct来自何处,为什么不将其强制转换为delete以匹配分配:
我个人认为您最好使用
一旦支持退出范围,您的 或者,您可以使用:
或 代码的行为未定义。您可能很幸运(也可能不是很幸运),并且可以与您的编译器一起使用,但这确实不是正确的代码。它有两个问题: 因此,要完全正确,您想做这样的事情:
是的,这将导致内存泄漏。 除了C Gotchas之外,请参见以下内容:http://www.informit.com/articles/article.aspx?p=30642,为什么。 Raymond Chen解释了向量 恕我直言,您应该将删除内容修复为:
而不是切换到 当然,由于原始分配中的强制转换,我上面显示的更简单的更改是错误的,应该为
所以,我想毕竟毕竟切换到 C标准明确规定:
它可能会泄漏内存,它不会泄漏内存,或者它可能会导致系统崩溃。确实,我测试过您的代码的C实现在delete表达式处中止了程序执行。 如其他帖子中所强调的: 1)调用new / delete分配内存,并可以调用构造函数/析构函数(C '03 5.3.4 / 5.3.5) 2)将 从源头上看,似乎有人进行了搜索并替换了
如果应调用STRUCT的构造函数,则可以考虑分配内存,然后使用放置
n n 如果您确实必须执行此类操作,则可能应该直接调用运算符
我相信以这种方式调用可以避免调用构造函数/析构函数。 这是您要引用的数组删除([]),而不是向量删除。 我目前无法投票,但slicedlime的答案比Rob Walker的答案更好,因为问题与分配器或STRUCT是否具有析构函数无关。 还请注意,示例代码不一定会导致内存泄漏-这是未定义的行为。几乎任何事情都可能发生(从没坏到很远的崩溃)。 示例代码导致未定义的行为,简单明了。 slicedlime的回答很直接,很直率(要注意的是,由于向量是STL,因此应将"向量"一词更改为"数组")。 C FAQ(第16.12、16.13和16.14节)很好地介绍了此类内容: http://www.parashift.com/c -faq-lite / freestore-mgmt.html#faq-16.12 是的,因为您可以使用new []进行分配,但可以使用delelte进行取消分配,所以在这里,malloc / free是更安全的,但是在c中,您不应使用它们,因为它们将不处理(de)构造函数。 您的代码也将调用解构函数,但不会调用构造函数。对于某些结构,这可能会导致内存泄漏(如果构造函数分配了更多的内存,例如用于字符串) 更好的做法是正确执行,因为这也会正确调用任何构造函数和反构造函数
您可以将其回退到BYTE *并删除:
n 始终最好保持对任何资源的获取/释放尽可能平衡。
您正在混合C和C的做事方式。为什么分配的资源超过STRUCT的大小?为什么不只是"新STRUCT"?如果必须执行此操作,则在这种情况下使用malloc和free可能会更清楚,因为那样的话,您或其他程序员可能不太可能对分配的对象的类型和大小进行假设。 @马特·克鲁克申克 "好吧,在VS2005上进行实验,我无法从vector new进行的内存标量删除中得到诚实的泄漏。我猜这里的编译器行为是"未定义的",是我可以召集的最佳防御方法。" 我不同意这是编译器行为,甚至是编译器问题。正如您所指出的那样,关键字" new"将被编译并链接到运行时库。这些运行时库以独立于OS的一致语法处理对OS的内存管理调用,并且这些运行时库负责使OS,Linux,Windows,Solaris,AIX等操作系统之间的malloc和新工作保持一致。这就是我提到可移植性参数的原因;试图向您证明运行时实际上也不管理内存。 操作系统管理内存。 操作系统的运行时库接口。在Windows上,这是虚拟内存管理器DLL。这就是为什么在GLIB-C库而不是Linux内核源代码中实现stdlib.h的原因。如果在其他操作系统上使用GLIB-C,则将执行malloc更改以进行正确的OS调用。在VS,Borland等中,您将永远找不到与其实际管理内存的编译器一起提供的任何库。但是,您将找到malloc的特定于操作系统的定义。 由于我们拥有Linux的源代码,因此您可以查看一下malloc在其中的实现方式。您将看到malloc实际上是在GCC编译器中实现的,该编译器反过来基本上在内核中进行了两个Linux系统调用来分配内存。永远不要,malloc本身,实际上是在管理内存! 别从我这里拿走它。阅读源代码到Linux OS或您可以看到什么K 使用运算符new和delete:
@马特·克鲁伊克(Matt Cruikshank) C运行时库进行OS系统调用,并且由OS管理堆。您的部分正确之处在于,运行时库指示何时释放内存,但是,它们实际上并没有直接遍历任何堆表。换句话说,您链接的运行时不会将代码添加到您的应用程序中以遍历堆进行分配或取消分配。在Windows,Linux,Solaris,AIX等中就是这种情况。这也是为什么您不会在任何Linux内核源代码中对malloc进行优化,也不会在Linux源代码中找到stdlib.h的原因。了解这些现代操作系统的虚拟内存管理器会使事情变得更加复杂。 是否想知道为什么可以在1G盒子上调用2g RAM的malloc并仍然返回有效的内存指针? 使用三个表在内核空间内管理x86处理器上的内存管理。 PAM(页面分配表),PD(页面目录)和PT(页面表)。这是我所说的硬件级别。 OS内存管理器(而不是C应用程序)要做的一件事是,在引导期间借助BIOS调用找出盒中安装了多少物理内存。操作系统还处理异常,例如当您尝试访问内存时,您的应用程序也没有权限。 (GPF一般保护故障)。 也许我们在说同样的话Matt,但是我想您可能会稍微混淆一下引擎盖下的功能。我过去经常维护一个C / C编译器... @ericmayo-薄饼。好吧,尝试使用VS2005,我无法从vector new进行的内存中标量删除中得到诚实的泄漏。我猜编译器的行为在这里是"未定义的",这是我可以召集的最佳防御方法。 您必须承认,按照原始海报所说的那样做确实很糟糕。
不过,这种逻辑并没有真正成立。我的断言是,编译器的运行时可以管理操作系统返回给它的内存块中的内存。大多数虚拟机就是这样工作的,因此在这种情况下您对可移植性的争论没有多大意义。 我认为这不是内存泄漏。
这将转换为操作系统中的内存分配调用,并在该调用中返回指向该内存的指针。在分配内存时,将知道 因此,已分配的内存被"记录"在操作系统的全局内存分配表中。内存表由它们的指针索引。因此,在相应的delete调用中,最初分配的所有内存都是可用的。 (内存碎片化也是该领域的热门主题。) 您会看到,C / C编译器不管理内存,而底层操作系统是。 我同意有更干净的方法,但是OP确实说这是旧代码。 简而言之,我没有看到内存泄漏,因为公认的答案认为会有一个。 Len:问题在于pStruct是STRUCT *,但是分配的内存实际上是某种未知大小的BYTE []。因此delete [] pStruct不会取消分配所有已分配的内存。 Rob Walker的回复很好。 另外,如果您没有任何构造函数或/和析构函数,那么您基本上需要分配和释放大量原始内存,请考虑使用free / malloc对。 ericmayo.myopenid.com太错了,以至于有人应声望他。 C或C运行时库正在管理由操作系统按块分配给它的堆,就像您指出的那样,Eric。但是开发人员有责任向编译器指示应进行哪些运行时调用以释放内存,并可能破坏那里的对象。在这种情况下,必须使用向量删除(aka delete []),才能使C运行时将堆置于有效状态。当PROCESS终止时,操作系统足够智能以释放基础内存块这一事实并不是开发人员应该依靠的。这就像根本不调用delete一样。 |