一:利用swap进行内存收缩
引言:利用swap函数和匿名对象来实现对容器所占用内存的及时回收
#include<iostream>
#include<vector>
using namespace std;
void test01(){
vector<int>v;
for(int i=0;i<1000000;i++) //容器的容量相当大,并且占用的内存也很大
v.push_back(i);
cout<<"容器容量 "<<v.capacity()<<endl;
cout<<"容器当前元素个数 "<<v.size()<<endl;
v.resize(10);//利用resize函数重新确定了元素个数,可以看出resize后容器容量很大,但实际用到的很少,这时候就得用到内存收缩
cout<<"内存收缩之前: "<<endl;
cout<<"容器容量 "<<v.capacity()<<endl;
cout<<"容器当前元素个数 "<<v.size()<<endl;
vector<int>(v).swap(v); //关键的内存收缩语句
cout<<"内存收缩之后: "<<endl;
cout<<"容器容量 "<<v.capacity()<<endl;
cout<<"容器当前元素个数 "<<v.size()<<endl;
}
int main() {
test01();
}
关键代码分析:vector<int>(v).swap(v);
前半部分vector<int>(v)就是一个匿名对象,通过拷贝构造函数来利用用已有容器中的元素来为其初始化,但是此匿名对象的capacity就是之前容器的size,然后再调用swap函数就能把两个容器所有的全部互换,而匿名对象的生存期只是这一行代码,到下一行代码就会被系统自动收回,这样就巧妙地完成了容器内存的收缩,
二:预留内存
为什么要预留内存?
我们已经知道,c++vector容器在创立之初并未指定容量,他的容量是系统自动计算分配的。当容量不够时,编译器不会在容器后面直接接上一段,而是会直接再开辟一块新的比之前大一些的内存来存放扩大后的容器,然后把之前的那块内存释放掉。
因此如果数据量较大,可以一开始利用reserve预留空间
功能描述:
- 减少vector在动态扩展容量时的扩展次数
函数原型:
-
reserve(int len);
//容器预留len个元素长度,预留位置不初始化,元素不可访问。
示例代码:
1.未预留时:
#include<iostream>
#include<vector>
using namespace std;
void test01(){
vector<int>v;
int times=0; //记录开辟次数
int *p; //通过和times的配合使用来记录容器开辟内存的次数
for(int i=0;i<100000;i++){
v.push_back(i);
if(p!=&v[0])
{
p=&v[0];
times++;
}
}
cout<<"内存开辟次数为"<<times<<endl;
}
int main() {
test01();
}
不难看出,系统开辟了十八次内存,这是非常费工夫的,影响了程序的运行效率,所以我们要尽量减少内存的开辟次数,这就用到了内存的预留。
2.预留后
#include<iostream>
#include<vector>
using namespace std;
void test01(){
vector<int>v;
int times=0; //记录开辟次数
int *p; //通过和times的配合使用来记录容器开辟内存的次数
v.reserve(100000); //预留操作
for(int i=0;i<100000;i++){
v.push_back(i);
if(p!=&v[0])
{
p=&v[0];
times++;
}
}
cout<<"内存开辟次数为"<<times<<endl;
}
int main() {
test01();
}