std :: vector如何调整其内部缓冲区的大小?

时间:2019-05-12 14:35:33

标签: c++ stl

据我所知,C ++不支持C语言中的'realloc(void *,size_t)'这样的运算符。

但是,std :: vector应该有一个缓冲区来容纳数据,并且应该扩展或压缩缓冲区。

然后如何在没有'realloc'函数的情况下调整std :: vector缓冲区的大小?

是否仅通过分配新缓冲区,复制或移动所有元素并破坏先前的缓冲区来完成? 我认为这样效率低下。

4 个答案:

答案 0 :(得分:1)

  

据我所知,C ++不支持像'realloc(void *,size_t)'这样的运算符

C ++确实有std::realloc。但这不是(通常?)用于实现向量大小的调整。

  

然后如何在没有'realloc'函数的情况下调整std :: vector缓冲区的大小?

使用以下算法:

  • 分配新数组
  • 将内容复制或移动到新数组
  • 取消分配旧数组
  

是否只是通过分配新缓冲区,复制或移动所有元素并破坏先前的缓冲区来完成?

是的。

  

我认为效率不高。

您为什么这么认为?正是realloc所做的。当然,realloc有时有时能够跳过复制,具体取决于内存布局,而矢量通常无法做到这一点。与手动malloc化动态数组相比,这是vector的不幸缺点,但不一定有很大缺点。

有人提出了向标准分配器添加重新分配支持的建议,如果将其引入标准中,则将允许相同的优化:http://open-std.org/JTC1/SC22/WG21/docs/papers/2019/p0894r1.md

答案 1 :(得分:1)

除非容器知道对象是TriviallyCopiable的,否则不使用

std :: realloc 。

来源:https://en.cppreference.com/w/cpp/memory/c/realloc

  

因为重新分配可能涉及按字节复制(无论   无论是展开还是收缩),仅对象   在受保护的部分中,可以轻松地访问TriviallyCopyable类型   调用realloc之后的内存块。

     

一些非标准库定义了类型特征“ BitwiseMovable”或   “可重定位”,它描述的类型没有:

如果容器不知道对象是普通可复制的,则使用realloc扩展内存可能会导致数据损坏。

如果可以在容器上使用is_trivially_copiable,则可以,可以使用realloc。否则会导致不确定的行为。

否则,容器a)创建新内存,b)调用元素的复制或移动构造函数以将其移动到新内存c)释放旧内存。

答案 2 :(得分:0)

如果理论上为std::vector<bool>,则内部不会使用等效于 realloc 的事实,但是要研究g ++的实现(gcc版本6.3.0 20170516 / Raspbian):

  template<typename _Alloc>
    void
    vector<bool, _Alloc>::
    _M_reallocate(size_type __n)
    {
      _Bit_pointer __q = this->_M_allocate(__n);
      iterator __start(std::__addressof(*__q), 0);
      this->_M_impl._M_finish = _M_copy_aligned(begin(), end(), __start);
      this->_M_deallocate();
      this->_M_impl._M_start = __start;
      this->_M_impl._M_end_of_storage = __q + _S_nword(__n);
    }

所以它基于新分配,然后复制然后取消分配

答案 3 :(得分:-1)

std :: vector 具有resize函数,可让您根据需要扩展或压缩数组。如果确实发生了重新分配,它将自动将元素复制/移动到新分配中。这就是迭代器可能变得无效的原因。