在全局运算符new返回的指针上使用realloc

时间:2015-11-11 11:05:05

标签: c++ dynamic-memory-allocation

C ++中没有realloc;当然,您始终可以使用new分配新块,将旧块复制到新块,使用delete释放旧块。

问题在于realloc通常比这更快 - 当内存块重新调整大小时就会发生这种情况' - 即realloc的返回值恰好与参数指针值相同;这也避免了将内存从旧块复制到新块。

标准说什么 - 是否允许将全局new运算符返回的指针传递给realloc? (在glibc中,newmalloc都使用相同的分配器,因此这里不应该存在实际问题)。 C ++标准对此主题有什么要说的吗?

(当前的glibc标准C ++库不执行realloc,即使在向量中 - 因为一旦分配了一个对象,运行时就无法在旧内存块上调用析构函数并在新内存上调用new block - 如果内存块已被realloc移动了那么。如果标准库有一个就地realloc无法将参数块移动到的位置会更简单一个新的位置)

编辑:

实际上一些内存分配器具有就地realloc功能;这些当然是非标准的。

  • jemalloc 有一个名为rallocm的API,标记为ALLOCM_NO_MOVE
  • dlmalloc (Doug Lea malloc)有一个名为dlrealloc_in_place
  • 的API

如果您对全局运算符newdelete使用jemalloc或dlmalloc,那么您可以将这些非标准函数用于在它执行之前尝试就地realloc的向量类通过复制移动malloc。或者可以请求C ++标准委员会在标准中添加全局非移动重新分配方法。

编辑:

或者您可以通过malloc / realloc / free执行内存管理的向量类,但是如果元素类型是普通旧数据,则只能实例化此实现(即如果std::is_pod在向量所持有的类型上返回true,则为。

2 个答案:

答案 0 :(得分:6)

不,您不能将free / realloc与内置new混合。

使用std::vector可以获得您正在寻求的大部分功能。保证(AFAIK)矢量中的对象是连续存储的(就像旧样式数组一样),您可以获得指向存储的指针,并且可以以标准定义的方式调整数组的大小。似乎唯一缺少的是提供自己的存储空间的可能性(即拥有T*并获得std::vector<T>存储空间。

如果您确实需要(首先检查以下缺点),您可能会做的是替换newdelete的默认实现以使用malloc和{{1} }:

free

执行此操作后,您可以对void* operator new(size_t n) { return malloc(n); } void operator delete(void* p) { free(p); } 获取的指针使用realloc

正如Michael Walz所指出的那样,如果要分配的对象需要初始化,则需要注意。如果只是复制内存而无法移动对象,那可能会更糟糕(如果new无法调整块的大小,则会realloc执行此操作。这意味着除了愚蠢的结构之外,它在其他任何东西上都是无用的(即使这样,你最终会得到像C语义一样的未初始化数据 - 甚至不是零初始化的。)

此外,mallocfreerealloc与C ++强打字效果不佳。这个

答案 1 :(得分:2)

  

c ++中没有realloc;

这也是一件好事!这是一个可怕的想法。它不是一个功能 - 它是一整套功能,全部集于一身。

  • 想要使用realloc代替malloc吗? 你可以!
  • 想要使用realloc代替free吗? 你可以!
  • 想要增长内存块吗? 是的,是的,你可以!
  • 想缩小它吗? 为什么是,你也可以这样做。
  • 想要什么都不做? 当然可以。你甚至需要问?

这个膨胀的界面使得无法正确可靠地使用,即使你怀疑有错误,基本上没有错误输入这一事实也很难调试。再加上结果经常被错误地使用,你最多只能得到内存泄漏的配方!

所以,请不要想到使用realloc的新方法 - 特别是在C ++中。如果您看到使用它的代码将其更改而不使用它。 realloc需要死亡

  

当然你总是可以用new分配一个新块,将旧块复制到新块,用删除释放旧块。

是的,你可以而且应该这样做。它有助于准确解释发生了什么,它比调用realloc并确定它是成功还是失败更不容易出错,并且在通过调用构造函数和析构函数分配数组时将始终做正确的事情。在合适的时间。

  

问题在于realloc通常比这更快 - 当内存块重新调整大小时就会发生这种情况&#39; - 这就是realloc的返回值恰好与参数指针值相同;这也避免了将内存从旧块复制到新块。

在充分尊重的情况下,程序的最大瓶颈可能不是内存复制。从C ++ 11开始,它给了我们移动语义,这比以往任何时候都更有可能。

当然,仅仅因为它不太可能并不意味着它是不可能的。如果你真的需要优化这种情况(通过彻底的性能分析证明),你可能会更好地考虑避免重新分配的方法,或花时间调整应用程序并调整其​​行为以引起它从一开始就分配更多内存,减少重新分配的需要和/或频率。