关于内存分配和C++

3
我引用MSDN上的话:http://msdn.microsoft.com/en-us/library/aa366533(VS.85).aspx
malloc函数的缺点是它依赖于运行时。new操作符的缺点是它依赖于编译器和语言。
现在有几个问题:
a) 我们说malloc依赖于运行时,这是什么意思?有哪些动态内存分配函数可以独立于运行时?这个说法听起来真奇怪。
b) new操作符是依赖于语言的吗?当然应该是的,对吗?HeapAlloc、LocalAlloc等是不是独立于语言的?
c) 纯性能方面,MSVC提供的例程更可取吗?
阿尔潘

1
评论他的回答,不要在这里留言。 - Puppy
对我来说真的很难理解;当然,每个运行时进行的“真实”内存请求都是运行时相关的。新操作符当然是语言相关的...但编译器相关?如果我们谈论C ++,它是标准化的,我期望new的行为不依赖于编译器;它如何实现其目的当然是编译器相关的(但这也是一个不重要的细节),而且也与系统有关(就像malloc一样)。 - ShinTakezou
4个回答

5
当使用动态链接库时,使用malloc和new可能会出现问题。根据构建选项,动态链接库可能具有其自己的CRT副本。这使它使用自己的堆来分配内存,与EXE使用的堆不同。这导致一个模块分配内存,另一个模块释放内存时失败。当您使用STL时非常常见。
解决此问题的一种方法是使用/MD选项编译代码。这将强制使用存储在其自己的DLL中的CRT的共享副本。问题解决了,现在只有一个分配器,使用单个堆。
这个问题也会在COM中出现,它允许不同的语言进行交互。它们当然不会共享分配器,因为这些语言具有不同的运行时支持库。按照合同,COM代码必须使用由COM运行时支持提供的单个分配器CoTaskMemAlloc()。
请注意,HeapAlloc()无法解决此问题。它需要一个由HeapCreate()返回的堆句柄。不同的模块必须共享该句柄以避免麻烦。
更新:在VS2012中解决了此问题,CRT现在从共享堆中分配,默认为进程堆(GetProcessHeap函数)。

2

a) 在这种情况下,我认为他们将“运行时库”简化为“运行时”。换句话说,它取决于您的C库中的实现。

b) 确实,new是C ++特定的。HeapAlloc等在技术上可用于C和C ++。

c) 它们不能用于创建C ++对象,因为它们不会调用构造函数,所以这一点相当无关紧要。在C ++中,您应该使用new和delete。


如果您想使用可移植的分配器,请重新定义全局 operator new - Ben Voigt
更不用说HeapAlloc和它的伙伴们也是Windows特有的——如果你使用它们,想要使你的代码可移植,唯一的方法就是为其他平台编写自己的HeapAlloc...何必呢?直接使用malloc/free或new/delete不就行了吗? - George

0

a) 这意味着malloc的行为取决于您编译的C运行时版本。

b) HeapAlloc和LocalAlloc是Win32 API函数。它们确实都是运行时和语言无关的。

c) 不知道运行时例程如何实现,这个问题无法回答。我怀疑它们的性能是相当的。无论如何,如果您选择使用new运算符,则始终可以在以后覆盖它(if necessary)。记住,过早优化是万恶之源。;)

最后的提示:LocalAlloc和GlobalAlloc非常慢。除非被一个古老的Win32 API强制使用,否则不应该使用它们。


0

哇,这是一个奇怪的声明出现在文档中没有附带解释。它可能是从C++引入时遗留下来的吗?对于您的问题,我只能猜测答案:

a)也许他们的意思是与链接/加载时间分配进行对比,例如全局变量、常量和静态数据。或者他们的意思是与堆栈分配进行对比,例如alloca系列。

b)他们可能会引起注意的是,您不应该使用C++ new分配内存,然后将该内存的所有权传递给库例程,该例程可能会free()它。因此,在这种意义上,分配的结果是特定于语言的。

c)使用C++ newdelete。您必须假设MSVC运行时中的基础C++分配器与C样式系统调用一样快,如果不是相同的话。只需记住,newdelete不仅仅是分配和释放内存。它们不能完全替代mallocfree或其他C样式分配器。


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