#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
class My_print
{
public:
void operator()(int val) {
cout << val << " ";
}
};
void test01()
{
vector<int>v;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
}
cout << "v的容量为: " << v.capacity() << endl;
cout << "v的大小为: " << v.size() << endl;
}
int main()
{
test01();
return 0;
}
初始阶段
定义了一个vector<int>
类型的变量v
,此时v
为空,容量和大小都为0。通过for
循环,使用push_back
方法将0到99999这10万个整数依次添加到v
中。
随着元素的不断添加,v
的大小逐渐增加,容量也会根据需要动态增长。vector
的容量增长策略通常是每次扩容时容量变为原来的两倍左右(不同编译器实现可能略有差异),以减少内存分配的次数,提高效率。当添加完10万个元素后,容器v
的大小为100000,容量却到达了约140000
当重新为容器指定大小之后:
调用resize
方法
使用v.resize(3)
将v
的大小重新指定为3。这意味着v
中只保留前3个元素,即0、1、2,其余元素被删除。但是,vector
的容量不会因为resize
方法的调用而自动减小。容量的减小通常需要手动调用如swap,以及shrink_to_fit
等方法来实现。所以,此时v
的大小为3,但容量仍保持不变,还是之前的较大值。
这种现象体现了vector
在动态调整大小时,容量和大小的变化规律是不同的。大小可以根据元素的增减直接变化,而容量的变化则相对独立,不会因为resize
等方法导致大小减小就立即减小,这是为了在后续可能的元素添加操作中,避免频繁的内存重新分配,提高操作效率。
巧用swap:
/*
vector<int>(v) - 匿名对象/临时对象(利用v调用拷贝构造函数,所创造出的一个(无名)对象)
编译器会按照v,目前所用的元素个数来初始化匿名对象(v),即(v) = 3;
.swap(v)本质:类似于指针的交换,进行容器的交换
交换前: 交换后:
v -> 原容器(140000) v -> 匿名容器(3)
(v) -> 匿名容器(3) ((v) -> 原容器(140000)) <-->等待回收
匿名对象特点:当匿名对象的代码执行结束后,系统会对其自动回收
*/
巧用swap收缩内存
vector<int>(v).swap(v);
这行代码是利用了vector
的临时对象和swap
方法来收缩内存。
vector<int>(v)
创建了一个v
的临时拷贝,这个临时拷贝的大小和容量都与v
相同,但由于它是临时对象,因此在表达式结束后就会被销毁。在销毁之前,先调用swap(v)
方法。
swap(v)
方法将临时拷贝的内存(此时大小为3,容量与v
相同)与v
的内存进行交换。交换后,v
的大小和容量都变成了临时拷贝的大小和容量,即大小为3,容量也为3(或略大于3,但肯定不会像之前那样很大)。
由于临时拷贝在表达式结束后被销毁,原来v
中多余的内存(容量大于3的部分)也随之被释放,从而实现了内存的收缩。
总结
通过“巧用swap收缩内存”的方式,可以有效地将vector
的容量减小到与大小相近的程度,从而释放多余的内存,优化内存使用。这种方法在需要减少vector
内存占用时非常有用,尤其是在处理大量数据后需要释放内存以提高程序性能的场景中。