【问题标题】:<vector> push_back implementation internal<vector> push_back 内部实现
【发布时间】:2015-02-16 09:40:47
【问题描述】:

在 std::vectors push_back 实现中,当 size()==capacity() 部分,它分配两倍的位置并复制 old 的元素,我想问,最有效的复制方式?

【问题讨论】:

  • 能否把你的问题说得更清楚些?您是在问向量如何复制旧元素并且您想这样做,还是什么?
  • 我不想这样做,我想知道vector是如何做到这一点的?
  • 然后简单的找到头文件,看看它是怎么做的?我的回答提供了如何“最有效地”做到这一点的选项。它没有描述您的 std::vector 实现很可能是做什么的。

标签: c++ vector data-structures stl push-back


【解决方案1】:

这在标准中并没有真正指定,而是留待实施。因此,不同的 C++ 库版本会以不同的方式执行此操作。但是,vectorallocator 必须用于任何分配和取消分配 (因此没有使用realloc())。

标准确实指定了,如果对象可以移动(而不是复制),那么它们应该被移动(自 C++11 起)。通常,将分配一个新的原始内存块,通常是前一个大小的两倍,然后将元素从前一个移动(或复制和销毁)到旧内存。对于一般情况,这种移动/复制必须一一完成(否则,如果不了解各个移动/复制构造函数的内部知识,就无法保证移动/复制的完整性)。当然,对于 pod(=plain old data)类型,可以通过 std::memcpy() 进行优化(并且很可能已实现)。

您可以尝试查看您的 C++ 库实现,但请注意,对于不熟悉元模板编程的人来说,代码可能非常不透明:由于各种优化(针对 pod、可移动类型等),代码很复杂。 )。

【讨论】:

  • 对,我忘记了那些被遗弃的分配器。当我用一些额外的东西做我的嵌入式向量替换类时,我根本没有添加分配器。
【解决方案2】:

听起来有点像您想自己实现std::vector&lt;&gt;
最有效的方法是首先避免重新分配,这通常但并非总是可行。

如果您事先知道接下来要push_back() 多少项目,您可以使用std::vector&lt;&gt;::reserve() 并完全避免重新分配。

如果你真的要自己实现,你可能想使用realloc(),尽管这是一个可怕的函数,它可以做 - 取决于参数值从malloc()free()到@ 987654327@。

这个函数有用的原因是,很有可能堆上的数据块后面还有空间。 realloc() 是唯一可以通过扩展此堆块大小来避免 100% 时间移动数据的函数,如果有足够的空间,则根本不接触数据。

使用realloc() 的缺点是你的“特殊性能”实现会放弃分配器的概念,并且无法处理需要复制构造函数调用等的元素类型。所以你最好不要命名你的向量向量而是一些东西像“SimpleDataVector”,并可能内置一些机制来检测滥用。

【讨论】:

  • 如果实现还使用placement new 等,则不会。
  • realloc 应该如何知道要使用哪个placement-new?
  • realloc() 只处理原始内存。如果它必须复制块的原始字节,它会返回一个不同的地址。如果它可以将数据保留在适当的位置,它会返回相同的地址。这应该是如何“修复”内容的标准。
  • "您放入 std::vector 的实例也不知道它们正在被移动到新位置。它们也没有参与该过程" - 这只是错了......构造函数和析构函数用于协调它,同时保持对象处于有效状态。例如,放置new 可以在旧缓冲区元素的析构函数调用发生之前,在新分配的更大缓冲区中移动或复制构造元素。
  • 是的,在某些特定情况下,它可以做任何需要的事情,我从不对此提出异议(就像我说的那样,微不足道的类型)。但是你真的应该至少提到条件!
猜你喜欢
  • 2014-08-27
  • 1970-01-01
  • 2017-09-15
  • 2012-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
相关资源
最近更新 更多