【发布时间】:2011-05-04 14:28:48
【问题描述】:
std::realloc 在 c++ 中很危险,如果 malloc 的内存包含非 pod 类型。似乎唯一的问题是std::realloc 如果不能原地增加内存,就不会调用类型析构函数。
一个简单的解决方法是使用try_realloc 函数。如果它不能就地增长,它不会分配新内存,而是简单地返回 false。在这种情况下,可以分配新内存,将对象复制(或移动)到新内存,最后释放旧内存。
这似乎非常有用。 std::vector 可以充分利用这一点,可能避免所有复制/重新分配。
抢先式阻燃:从技术上讲,这与 Big-O 性能相同,但如果向量增长是一个瓶颈即使 Big-O 保持不变,您的应用程序的 2 倍加速也很好。
但是,我找不到任何像 try_realloc 一样工作的 c api。
我错过了什么吗? try_realloc 没有我想象的那么有用吗?是否有一些隐藏的错误导致try_realloc 无法使用?
更好的是,是否有一些记录较少的 API 可以像 try_realloc 一样执行?
注意: 显然,我在这里使用库/平台特定代码。我不担心try_realloc 本身就是一种优化。
更新:
在 Steve Jessops 评论vector 是否会更有效地使用 realloc 之后,我写了一个概念证明来测试。 realloc-vector 模拟向量的增长模式,但可以选择重新分配。我在向量中运行了多达一百万个元素的程序。
作为比较,vector 必须分配 19 次,同时增长到一百万个元素。
结果,如果 realloc-vector 是唯一使用堆的东西,那么结果非常棒,3-4 分配,同时增长到百万字节的大小。
如果realloc-vector 与vector 一起使用,vector 的增长速度是realloc-vector 的 66%,结果不太乐观,在增长过程中分配了 8-10 倍。
最后,如果realloc-vector 与以相同速率增长的vector 一起使用,则realloc-vector 分配17-18 次。几乎没有比标准向量行为节省一个分配。
我不怀疑黑客可以通过游戏分配大小来节省成本,但我同意 Steve 的观点,即编写和维护这样一个分配器的巨大努力并没有带来任何好处。
【问题讨论】:
-
在不知道您要定位的平台的情况下,很难提供特定于平台的建议。
-
我忍不住想:如果你想要最好的性能,使用 vector.reserve() 这样你就根本不用增长向量了。
-
@kotlinski:但你不能总是那样做。否则向量类的动态增长属性无论如何都是多余的。
-
如果您的
vector持有的对象的复制性能很差,并且无论出于何种原因您都不能使用deque,那么也许您应该将您的vector更改为持有@987654343 @ 指向对象的实例。这样,复制操作将变得便宜很多。我不确定unique_ptr对象是否可以在标准容器中使用,但这会进一步减少复制开销。 -
为了能够在 C++ 中将 realloc(或类似的)与非 POD(普通旧数据)一起使用,您不仅需要能够在失败的情况下调用析构函数,而且在这种情况下缩小数组。如果数组正在增长,它还必须在数组的新成员上调用默认构造函数。可能需要考虑的另一件事是移动对象是否会导致某些问题;然后类可能需要实现一个 move 方法,该方法是一种析构函数,它具有对旧数据和新数据的引用,但移动的顺序可能很重要。
标签: c++ c memory-management realloc