【问题标题】:Realloc equivalent in C++C++ 中的 Realloc 等价物
【发布时间】:2013-02-10 05:53:35
【问题描述】:

是的,另一个reallocstd::vector 的问题。我知道你要说什么,我同意,忘记手动内存分配,只需使用std::vector。不幸的是,我的教授禁止我在这项作业中使用 STL 中的任何东西。

是的,我有一个 T 的动态数组,我需要调整它的大小,但我不能使用 std::vector。我可以回到黑暗时代并与malloc 和家人一起做所有事情,但如果我可以使用new,那就太棒了。

我读过很多帖子,每个人都说“不,你不能这样做,请使用std::vector”,但它们都是在 2011 年 8 月之前发布的,我希望事情可能会有所改变自 C++11 诞生以来。所以告诉我,我是幸运的,还是我必须恢复到 C 风格的内存分配?

【问题讨论】:

  • “很遗憾,我的教授禁止我在这项作业中使用 STL 中的任何东西。” - 没问题,std::vector 不在 STL 中,它在 C++ 标准库中。
  • @Rapptz:如果你想让你的代码真正工作,你就不能这样做。
  • @MichaelDorst H2CO3 所指的是,STL 是过时的第 3 方库的旧名称,而现在被错误地称为 STL 的所有内容都是 C++ 标准库的一部分.如果您有兴趣,请查看What's this STL vs. "C++ Standard Library" fight all about?..
  • @perreal 你的意思是malloc后跟一个副本,有时是,但是如果有空间,realloc不会复制,它只会分配更多空间。
  • @jogojapan 不管你想告诉我什么听起来很有希望,你能发布一个更详细的答案吗?

标签: c++ dynamic-memory-allocation


【解决方案1】:

无论如何,您都应该完全避免使用realloc,因为您不能像那样在 C++ 对象中移动。

  • 使用buf = new unsigned char[sizeof(T) * capacity] 创建新缓冲区
  • 将分配的unsigned char * 转换为T * 并从现在开始使用这些T 指针
  • 通过“放置new”构造新元素,如new (&buf[i]) T(original_copy)
  • 要将缓冲区复制到更大的缓冲区,首先分配新缓冲区,使用std::uninitialized_copy不是std::copy),然后使用buf[i].~T() 销毁旧缓冲区中的元素并释放使用 delete [] buf 的旧缓冲区。

所有这些都假设您不必担心异常安全,这对于分配来说可能是可以的。
请注意,在实际代码中,您必须保证异常安全,而这很多比这更乏味。

【讨论】:

  • 糟糕!使用static_cast<T*>(::operator new(sizeof(T) * cap)) 获取内存,如果有的话。然后使用placement new将东西粘在那里。这样,您可以使用普通的指针算法来标记您的第一个、最后一个和结束。我什至会说这会使分配的事情变得过于复杂,只会直接使用new T[capacity] 并需要默认的可构造性。
  • @Xeo:我不明白,为什么new unsigned char[] 不好,::operator new() 如何更好?关于默认可构造性:如果他走那条路,那么他还需要使用std::copy
  • 这个想法是你已经明确键入了内存。
  • @Xeo:你能详细说明一下吗?我不确定你是什么意思。在我的情况下,不是所有内容都明确输入了吗?
  • Re“你不能像那样在 C++ 对象周围移动”,好吧,虽然 std::vector 通常不能用于使用 realloc,但它确实可以在这样的 C++ 对象周围移动。问题不在于 realloc,而在于容器设计(需要简单的标准分配器)。 realloc 会为 合适的容器 提供非常好的性能提升,没问题(即大于 std::vector 的实现问题)。
【解决方案2】:

realloc 的问题在于可能会将现有数据移动到不同范围的连续地址。如果它需要这样做,鉴于它是一个 C 函数,数据被复制而没有任何对 C++ 对象生命周期的点头:

  • 不使用复制/移动构造函数
  • 之后不会为源对象调用析构函数

这可能会导致致命的后果 - 例如,当被移动的对象包含仍然指向正在腾出的内存区域中的地址的指针/引用时。

遗憾的是,普通的malloc 实现不允许回调挂钩,允许您用自己的 C++ 安全实现替换内存内容复制代码。如果您确定可以尝试找到一个更灵活的“malloc”库,但这不太可能值得麻烦和冒险。

因此,在一般情况下,您应该使用new 更改容量、复制/移动每个对象,然后使用delete 原件。

如果您确定您的数据足够简单,memcpy 样式的重定位不会造成不良后果,那么您可以使用realloc(风险自负)。

【讨论】:

    猜你喜欢
    • 2013-06-21
    • 2011-04-02
    • 2021-10-15
    • 2013-10-20
    • 2011-04-10
    • 2021-12-02
    • 2010-09-14
    • 2016-12-24
    相关资源
    最近更新 更多