【问题标题】:C++ standard vector resize() functionC++ 标准向量 resize() 函数
【发布时间】:2016-05-12 19:57:10
【问题描述】:

resize() 根据给定的大小添加/删除元素。 reserve() 保留内存空间,它不会重新分配内存。我的问题是,resize 是否也与向量容量相同,只是不会增加?

要添加,请结合:

 std::vector<X> vector;
 vector.reserve(5);
 vector.resize(5); 

有意义吗?是多余的吗?这里的目标是能够覆盖向量中的值,而无需向量分配任何额外空间。

【问题讨论】:

  • 作为测试,我使用 Visual Studio 注意到机器人调整大小和保留的容量保持不变。但是,这可能是对 VS 编译器的一些优化。
  • "reserve() 保留内存空间,它不会重新分配内存" -- 这应该是个问题吗?因为如果是陈述,那就错了。
  • reserve() 保留内存空间,不会重新分配内存。谁告诉你的?如果请求的大小大于容量,reserve 将分配更多内存。
  • 简短且非常简单,reserve 设置容量,resize 设置大小(可能还有容量)。

标签: c++ resize stdvector


【解决方案1】:

来自this site

  • resize():这使您可以将矢量的大小更改为您想要的任何大小。
    • 它将用元素填充底层缓冲区。
  • reserve():这会改变向量的容量。请注意,这不会改变向量的大小,它只是改变底层缓冲区的大小,以便在必须调整缓冲区大小之前为缓冲区的扩展提供更多空间。与调用resize() 不同,这不会改变程序的行为,只会改变性能(后续使用预留空间不会因增量预留而导致性能损失)。
    • 它不会限制缓冲区的大小。如果缓冲区空间不足,它将根据需要自动重新分配。

我的问题是调整大小是否也与 向量的容量只会不会增加? 要添加,将以下组合:

 std::vector<X> vector;
 vector.reserve(5);
 vector.resize(5);

有意义吗?是多余的吗?

vector.reserve(5); 在这种情况下是多余的。

这里的目标是能够覆盖向量中的值而不 让向量分配任何额外的空间。

对于这个目标,这取决于您希望如何覆盖这些值。

  • 如果你打算直接按索引写,那么你必须使用resize()
  • 如果你使用push_back(),那么reserve()会更好,这样你就可以避免创建X两次。

请记住,用于自动预订的算法是由实现定义的。有关性能方面的更多信息,请参阅here

【讨论】:

  • "与调用 resize() 不同,这不会改变程序的行为,只会改变性能。" ...你能解释一下你的意思吗?
  • 预留空间的后续使用不会对增量预留造成性能损失。
  • 我会在你的回答中这么说,而不是作为评论。
  • @JonathanPotter 更新了说明。谢谢。
【解决方案2】:

我不知道您从哪里获得有关 reserve 的信息,但如果您传递给它的数字大于向量的当前容量,它将重新分配,正如 capacity 函数所报告的那样。

至于resize,需要设置元素个数,如果容量不够,还需要重新分配。

至于你的代码sn-p:

std::vector<X> vector;
vector.reserve(5);
vector.resize(5);

如果您想分配尽可能少的数量以存储 5 个元素,这可能是有意义的。我这么说的原因是因为resize 可能会分配更多以期待以后更多的添加(需要明确的是,这只有在请求的大小大于容量时才会发生。resize 将永远不会导致重新分配如果请求大小 reserve 通常只是分配得足够多。允许分配更多,但我从未见过这样做的实现。

【讨论】:

    【解决方案3】:

    为了扩展@BenjaminLindley 的答案,在 GCC 中肯定存在差异。

    #include <iostream>
    #include <vector>
    
    int main()
    {
      std::vector<int> a, b;
    
      for (std::size_t i=0; i<20; ++i)
      {
        a.reserve(i); a.resize(i); // a: reserve-then-resize
        b.resize(i);               // b: resize directly
        std::cout << a.capacity() << "\t" << b.capacity() << "\n";
      }
    }
    

    输出(live demo):

    0   0
    1   1
    2   2
    3   4
    4   4
    5   8
    6   8
    7   8
    8   8
    9   16
    10  16
    11  16
    12  16
    13  16
    14  16
    15  16
    16  16
    17  32
    18  32
    19  32
    

    因此,至少对于 gcc,reserve-then-resize 会导致完全您要求的容量,而直接调整大小“提前计划”为预期的未来分配。

    【讨论】:

    • 我喜欢这个。很高兴看到一些实际测试会发生什么。看来push_back()triggers the samereserve() 的行为就像b
    • 是的,我早就料到了。重复的push_back()s 可能是std::vector 最常见的用例,并且以指数级增长容量是您摊销 O(1) 复杂性的原因。
    【解决方案4】:

    它们之间的主要区别在于 resize 允许您更改大小(增加或减少),而 reserve 仅保留系统的内存。调整大小通过调用默认构造函数或复制构造函数来初始化分配的内存,具体取决于所使用的调整大小的形式。

    两者都可能导致内存重新分配。

    【讨论】:

      【解决方案5】:

      在某些实现中,resize 几乎肯定会首先调用reserve。最近实现了std::vector 的变体,下面是std::vector::reserve 的精简和注释版本...(cmets 是为了让 OP 理解)...实际上大多数 STL 实现会稍微复杂一些比这个(用于调试目的);但其概念大致相同。

      template<typename T>
      void Vector<T>::reserve(SizeType sz){
              //if only the new size is greater than current capacity
              if(sz > m_capacity){
      
                  //allocate the new size
                  T* data = static_cast<T*>(SFAllocator<T>::allocate(sz));
      
                  //move all previous data
                  for(SizeType i=0; i < m_size; i++){
                      new(data+i) T(std::move(m_data[i]));  //! TODO: move if only noexcept;
      
                      //call the destructor on the moved item
                      call_destructor(m_data[i]);
                  }
      
                  //deallocate formerly used memory
                  SFAllocator<T>::deallocate(m_data);
      
                  //reassign the capacity to the new capacity
                  m_capacity = sz;
      
                  m_data = data; //reassign the data pointer
                  //size remains the same
              }
      

      下面是std::vector::resize 的精简和注释版本。正如您在下面看到的,resize 首先调用了reserve

      template<typename T>
      void Vector<T>::resize(SizeType sz){
          // resize it to fit at least fit to "sz"
          reserve(sz);
      
          //if higher size is requested
          if(sz > m_size)
              //default construct the remainder of the new uninitialized memory
              for(SizeType i= m_size; i < sz; i++)
                  new(m_data+i) T{}
      
          //if the container size is to get smaller
          else  
              for(SizeType i=sz; i<m_size; i++)
                  call_destructor(m_data[i]);  //delete the elements at indexes above "sz"
      
          m_size = sz;  //change container size.
      }
      

      【讨论】:

      • 谢谢。 C++ 11 会调用它吗?
      • Facebook 的 Folly 的 FBVector,替换 std::vector 调用 reserveresize... github.com/facebook/folly/blob/master/folly/FBVector.h#L919
      • 注意,C++ 是一种语言,STL 是它的默认库。编译器产品通常将实现与实际编译器捆绑在一起。比如,............GCC libstdc++............ Clang --> libcxx,............ MSVC --> Dinkumware......
      • 我刚刚检查了 GCC 4.6 的 libstdc++,是的,它称之为(resize 的一种变体)
      猜你喜欢
      • 1970-01-01
      • 2015-02-17
      • 2013-05-06
      • 2011-08-15
      • 2014-06-02
      • 2011-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多