巧用 - 接口swap

#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内存占用时非常有用,尤其是在处理大量数据后需要释放内存以提高程序性能的场景中。