C++ vector中resize方法的作用与实现细节解析

0 次阅读

std::vector 是 C++ 标准库中最常用的动态数组容器之一,它提供了灵活的内存管理能力,可以根据元素数量自动扩容。resize() 作为 vector 中的重要成员函数,经常用于调整容器大小,但很多开发者对它与 reserve()push_back() 等方法之间的区别并不清楚。

理解 vector::resize() 的作用机制,不仅有助于编写更高效的 C++ 程序,也能避免因为误用导致的性能问题或逻辑错误。

一、vector::resize()基本作用

resize() 方法用于改变 std::vector 当前存储的元素数量,也就是修改 vector 的 size()

函数原型如下:

C++
void resize(size_type count);

void resize(size_type count, const value_type& value);

其中:

  • count 表示调整后的元素数量。

  • value 表示当新增元素时,用于初始化新元素的默认值。

简单来说:

  • 新大小大于当前 size:增加元素。

  • 新大小小于当前 size:删除末尾元素。

  • 新大小等于当前 size:不发生变化。

例如:

C++
#include 
#include 

int main()
{
    std::vector<int> nums = {1, 2, 3};

    nums.resize(5);

    for (int n : nums)
    {
        std::cout << n << " ";
    }

    return 0;
}

输出:

1 2 3 0 0

原 vector 有 3 个元素,调用 resize(5) 后增加两个 int 类型元素,由于 int 默认初始化为 0,因此新增位置保存为 0。


二、resize扩容时的实现原理

当调用:

C++
vector.resize(newSize);

如果:

C++
newSize > size()

vector 需要增加元素数量。

内部执行过程大致如下:

  1. 判断当前容量 capacity() 是否足够。

  2. 如果容量足够,直接在已有内存空间中构造新元素。

  3. 如果容量不足,则重新申请更大的内存。

  4. 将旧元素移动或复制到新内存。

  5. 销毁旧内存。

  6. 更新 size。

例如:

C++
std::vector<int> v = {10, 20, 30};

v.resize(6);

执行前:

size = 3
capacity >= 3

执行后:

size = 6
capacity >= 6

新增三个元素:

10 20 30 0 0 0

需要注意的是,resize() 改变的是元素数量,而不仅仅是分配空间。


三、resize与capacity的关系

很多 C++ 初学者容易混淆 size()capacity()

size()

表示当前 vector 中实际存在的元素数量:

C++
std::vector<int> v = {1,2,3};

std::cout << v.size();

输出:

3

说明 vector 中有 3 个元素。


capacity()

表示 vector 当前已经分配的内存能够容纳多少元素:

C++
std::cout << v.capacity();

可能输出:

4

也可能输出:

8

具体数值由编译器实现决定。


调用:

C++
v.resize(100);

之后:

C++
v.size();

一定变成:

100

但是:

C++
v.capacity();

可能大于等于:

100

因此:

  • size 代表实际元素数量。

  • capacity 代表预留空间大小。


四、resize缩小时发生什么

当新的大小小于当前 size:

C++
std::vector<int> v = {1,2,3,4,5};

v.resize(2);

执行后:

1 2

后三个元素会被销毁。

但是:

C++
v.capacity();

通常不会减少。

例如:

C++
std::cout << v.capacity();

可能仍然输出:

5

甚至更大。

原因是 vector 会保留已经申请的内存,以便未来继续添加元素,提高性能。

如果希望释放多余容量,可以使用:

C++
v.shrink_to_fit();

例如:

C++
v.resize(2);
v.shrink_to_fit();

不过需要注意:

shrink_to_fit() 只是请求释放,不是强制要求,具体是否执行由标准库实现决定。


五、resize与reserve的区别

这是 C++ vector 使用中最容易混淆的问题之一。

reserve()

用于提前分配内存:

C++
vector.reserve(n);

它只改变容量:

C++
std::vector<int> v;

v.reserve(100);

std::cout << v.size();

输出:

0

因为没有创建任何元素。


resize()

用于改变元素数量:

C++
v.resize(100);

执行后:

C++
v.size();

结果:

100

同时创建 100 个元素。


对比:

方法修改size修改capacity创建元素
resize可能
reserve

使用场景:

提前知道元素数量:

C++
std::vector<int> data;

data.reserve(1000);

for(int i = 0; i < 1000; i++)
{
    data.push_back(i);
}

适合使用 reserve()

需要直接访问指定位置:

C++
std::vector<int> data;

data.resize(100);

data[50] = 10;

适合使用 resize()


六、resize新增元素的初始化规则

不同类型的元素,初始化方式不同。

基本类型

例如:

C++
std::vector<int> v;

v.resize(3);

结果:

0 0 0

也可以指定默认值:

C++
v.resize(3, 100);

结果:

100 100 100

自定义类型

例如:

C++
class Person
{
public:
    Person()
    {
        std::cout << "constructor";
    }
};

std::vector<Person> people;

people.resize(5);

vector 会调用默认构造函数创建 5 个对象。

如果对象没有默认构造函数:

C++
class Person
{
public:
    Person(int age){}
};

那么:

C++
people.resize(5);

会编译失败。

因为 resize 需要知道如何创建新增元素。


七、resize对迭代器和引用的影响

调用 resize 后,需要注意迭代器失效问题。

扩容导致失效

例如:

C++
std::vector<int> v = {1,2,3};

auto it = v.begin();

v.resize(100);

如果发生重新分配:

  • 原来的 iterator 失效。

  • 原来的指针失效。

  • 原来的引用失效。

原因是元素可能已经移动到新的内存地址。


缩小导致部分失效

例如:

C++
std::vector<int> v = {1,2,3,4};

auto it = v.begin()+3;

v.resize(2);

元素 4 被删除,因此:

C++
it

已经失效。

但是前两个元素的引用通常仍然有效。


八、resize的时间复杂度分析

resize() 的复杂度取决于操作类型。

增加元素

如果无需重新分配:

时间复杂度:

O(n)

其中 n 是新增元素数量。

因为需要构造新的元素。


如果发生扩容:

时间复杂度:

O(size + n)

因为需要移动旧元素,同时创建新元素。


删除元素

缩小时:

O(size - newSize)

需要销毁被删除的对象。

对于 int 等简单类型,销毁成本非常低。

对于复杂对象:

C++
vector<MyClass>

可能涉及析构函数调用。


九、resize常见使用场景

1. 提前创建固定大小数组

例如:

C++
std::vector<int> buffer;

buffer.resize(1024);

buffer[0] = 100;

相比连续 push_back,更适合随机访问。


2. 修改二维数组大小

例如:

C++
std::vector<std::vector<int>> matrix;

matrix.resize(5);

for(auto& row : matrix)
{
    row.resize(5);
}

创建:

5 × 5

二维结构。


3. 文件读取缓冲区

例如:

C++
std::vector<char> buffer;

buffer.resize(fileSize);

read(buffer.data(), fileSize);

可以直接获取连续内存。


十、使用resize时的注意事项

1. 不要用resize代替reserve

错误方式:

C++
vector<int> v;

v.resize(1000);

for(int i=0;i<1000;i++)
{
    v.push_back(i);
}

这样会产生:

1000个默认元素 + 1000个新增元素

最终 size:

2000

正确方式:

C++
vector<int> v;

v.reserve(1000);

for(int i=0;i<1000;i++)
{
    v.push_back(i);
}

2. resize不会自动释放内存

很多开发者认为:

C++
v.resize(0);

会释放所有内存。

实际上:

C++
v.size()==0

但:

C++
v.capacity()

可能仍然很大。

如果需要释放:

C++
std::vector<int>().swap(v);

或者:

C++
v.clear();
v.shrink_to_fit();

3. 大对象避免频繁resize

如果 vector 存储大型对象:

C++
vector<BigObject>

频繁调整大小可能导致:

  • 大量构造。

  • 大量析构。

  • 内存复制。

应提前规划容量。


十一、vector::resize源码逻辑简析

不同标准库实现略有差异,但核心流程类似:

C++
void resize(size_type n)
{
    if(n > size())
    {
        insert(end(), n - size(), value_type());
    }
    else if(n < size())
    {
        erase(begin()+n, end());
    }
}

实际 STL 实现会进行更复杂的优化:

  • 判断容量。

  • 使用移动构造。

  • 使用内存分配器。

  • 进行异常安全处理。

现代 C++ 中通常优先使用移动语义:

C++
T(T&& other);

减少对象复制,提高效率。


十二、总结

std::vector::resize() 是 C++ vector 中用于调整元素数量的重要方法,它不仅改变 size,还会根据情况创建或销毁对象。

核心要点如下:

  • resize() 修改元素数量。

  • 增大 size 会创建新元素。

  • 减小 size 会删除尾部元素。

  • resize 可能触发内存重新分配。

  • resize 与 reserve 作用完全不同。

  • resize 后需要关注迭代器失效问题。

  • 对大型对象使用时需要考虑性能影响。

掌握 vector::resize() 的内部机制,可以帮助开发者更加合理地管理动态数组,提高 C++ 程序运行效率和稳定性。