C++ 标准向量 resize() 函数

C++ standard vector resize() function

resize() adds/removes 元素基于给定的大小。 reserve() 保留内存 space 并且不会重新分配内存。我的问题是 resize 是否也一样,因为 vector 的容量只会不增加?

要添加,将组合:

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

有什么意义吗?它是多余的吗?这里的目标是能够覆盖向量中的值,而无需向量分配任何额外的 space.

来自this site

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

The question I have is whether resize also works the same as in the capacity of the vector will only not increase? To add, would a combination of :

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

make any sense? Is it redundant?

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

The goal here is to be able to overwrite values in the vector without having the vector allocate any extra space.

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

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

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

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

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

我不知道你从哪里得到关于 reserve 的信息,但如果你传递给它的数字大于矢量的当前容量,它将重新分配,如 capacity 所报告的功能。

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

至于你的代码片段:

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

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

在某些实现中,resize 几乎肯定会先调用 reserve。最近实现了 std::vector 的一个变体,下面是 std::vector::reserve 的精简和注释版本......(评论是为了 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.
}

为了扩展@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,预留然后调整大小会正好 您要求的容量,而直接调整大小“提前计划”预期的未来分配。