C++ vector内存分配及正确释放
谈到vector的内存分配,首先要知道size()和capacity()方法的区别。前者求的是实际的vector元素个数,后者求的是实际占用内存的个数,一般来说,申请的内存capacity()是大于或等于size()的1.清空vector的元素:clear()2.释放内存:clear() +shrink_to_fit() 或 swap()1.clear()1.使用clear()不会真正释放内存,c
目录
2.【非强制】释放内存:clear() + shrink_to_fit()
内存分配
1.C++ vector:相当于一个动态数组,它的内存会随着size的增加而不断的增长。
2.内存分配的两个函数:size()返回实际占用内存的个数
capacity(),返回实际申请的空间大小,一般来说,capacity >= size 。
3.扩容:当capacity和size相等时,vector就会扩容,capacity会成倍增长。一般来说,vector扩容后内存是原来的2倍,但也有说扩容后是原来内存的1.5倍,与操作系统相关。
4.扩容原理:以vector最常用的push_back为例,调用push_back时,若当前容量(capacity)已经不能够容纳新的元素,即此时capacity=size,那么vector会重新申请一块内存,把之前的内存里的元素拷贝到新的内存当中,然后把push_back的元素拷贝到新的内存中,最后要析构原有的vector并释放原有的内存。这个过程的效率是极低的,为了避免频繁的分配内存,C++每次申请内存一般都会成倍的增长,例如之前是4,那么重新申请后就是8,以此类推。
5.扩容隐患:由于每次内存分配成倍数申请,可能引发内存分配不足抛出bad_alloc异常,推荐以下的解决方案:如何在C++中处理bad_alloc? | 经验摘录。
3.扩容验证代码:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> vec(10);
cout << "vec.size: "<< vec.size() <<endl;
cout << "vec.capacity;"<< vec.capacity()<<endl;
vec.push_back(1);
cout << "vec.size: "<< vec.size() <<endl;
cout << "vec.capacity:"<< vec.capacity()<<endl;
}
运行结果如图:
需要内存释放的场景
什么情况下需要释放vector呢?
1.vector是局部变量的不用释放。
2.采用智能指针创建的vector不用释放。
3.动态分配出来的vector,但数据量不大,对内存影响很小不用释放,但未来重新使用这个vector,插入大量新元素,用swap清空比较好。
4.动态分配出来的vector且包含大数据集的需要。
1.局部变量不需要释放:C++ 在其生命周期结束时自动销毁,并自动释放其占用的内存。因此当myFunc执行完成完,vec即使包含大量对象内存也能被自动释放。
#include <iostream>
#include <vector>
using namespace std;
void myFunc() {
vector<int> vec(1000000, 123);
}
int main() {
myFunc();
return 0;
}
2.动态分配需要释放的:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int>* vec = new vector<int>(1000000, 123);
vector<int>().swap(*vec);
cout << "After swap - size: " << vec->size() << ", capacity: " << vec->capacity() << endl;
delete vec;
return 0;
}
3.智能指针分配的vector不需要释放:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
int main() {
unique_ptr<vector<int>> vec(new vector<int>(1000000, 123));
cout << "vec size: " << vec->size() << ", capacity: " << vec->capacity() << endl;
cout << "离开作用域后,vec自动销毁,不需要swap释放内存" << endl;
return 0;
}
内存释放
1.清空vector的元素:clear()
使用clear()不会真正释放内存,capacity()无变化
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> vec;
//手动空间100
vec.reserve(100);
vec.push_back(1);
vec.push_back(2);
cout <<"vec.size(): " << vec.size() << endl;
cout <<"vec.capasity(): " << vec.capacity() << endl;
vec.clear();
cout <<"After vec.size(): " << vec.size() << endl;
cout <<" After vec.capasity(): " << vec.capacity() << endl;
return 0;
}
运行结果如图:
2.【非强制】释放内存:clear() + shrink_to_fit()
shrink_to_fit()官方定义Requests the container to reduce its capacity to fit its size, 即减少容量至适应其自身大小)。但shrink_to_fit()某些情况下非强保证执行,与编译器和内存分配策略息息相关。所以clear+shrink_to_fit方法可以作为一种参考。如果想要安全释放,还是推荐用3中的swap方法。
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> vec;
//手动空间100
vec.reserve(100);
vec.push_back(1);
vec.push_back(2);
cout <<"vec.size(): " << vec.size() << endl;
cout <<"vec.capasity(): " << vec.capacity() << endl;
vec.clear();
vec.shrink_to_fit();
cout <<"After vec.size(): " << vec.size() << endl;
cout <<"After vec.capasity(): " << vec.capacity() << endl;
return 0;
}
运行结果如图:
3.【推荐】释放内存:swap()
1.swap的用法有以下两种:
1.释放vector中多余的空间
2.释放整个vector空间
构造函数也不同:
释放整个vecter空间:vector<int> ().swap(vec);
释放vec中多余空间:vector<int> (vec).swap(vec);
原理:
采用swap释放空间原理:vector()使用默认构造函数建立临时vector对象,再对该临时对象上调用swap()成员,swap调用之后对象vector占用的空间就等于一个默认构造的对象的大小,临时对象就具有原来对象vector的大小,而临时对象随机被析构,从而其占用的空间被释放调。
举个例子:执行vector<int>().swap(vec)语句时,实际是执行三步操作:
1.创建一个临时,无指向的vector<int> 对象。
2.使用 swap 方法将临时对象与 vec 交换。
3. 通过交换,vec 的资源释放并且临时对象也被销毁,从而释放其内存。
例:vector释放全部占用内存
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> vec;
//手动空间100
vec.reserve(100);
vec.push_back(1);
vec.push_back(2);
cout <<"vec.size(): " << vec.size() << endl;
cout <<"vec.capasity(): " << vec.capacity() << endl;
vector<int> ().swap(vec);
cout <<"After vec.size(): " << vec.size() << endl;
cout <<"After vec.capasity(): " << vec.capacity() << endl;
return 0;
}
运行结果如图:
4.双层vector释放内存
方法一:循环清空每个内部vector并使用
shrink_to_fit()
方法来回收内存。但这种方法不是百分百有效。方法二:遍历外层对象中的每个内部对象,使用
vector<int>().swap(vec);
方法来释放每个内层对象的内存。方法三:重新分配一个新的双层vector,swap交换并销毁原来的双层vector。
另外,方法一和方法二中,销毁顺序是从最深层开始逐步向外释放每一层的内存。这样做的好处是确保内存被适当和完全地释放,从而避免任何潜在的内存泄漏或不必要的内存占用。
方法一:clear+shrink_to_fit释放
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<vector<int>> vec;
vec.push_back({1,2});
vec.push_back({4,5,6});
vec.push_back({7,8,9});
cout<<"vec outer size: "<<vec.size()<<endl;
for(const auto& i: vec){
cout <<"vec vinner size: "<<vec.size() <<" , vec inner capacity: "<<i.capacity()<<endl;
}
//释放内层
for(auto& i :vec){
i.clear();
i.shrink_to_fit();
}
//释放外层
vec.clear();
vec.shrink_to_fit();
cout<<"after releasing vec outer size: "<<vec.size()<<endl;
}
方法二:逐层采用swap释放
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<vector<int>> vec;
vec.push_back({1,2});
vec.push_back({4,5,6});
vec.push_back({7,8,9});
cout<<"vec outer size: "<<vec.size()<<endl;
for(const auto& i: vec){
cout <<"vec vinner size: "<<vec.size() <<" , vec inner capacity: "<<i.capacity()<<endl;
}
//释放内层
for(auto& i :vec){
vector<int>().swap(i);
}
//释放外层
vector<vector<int>>().swap(vec);
cout<<"after releasing vec outer size: "<<vec.size()<<endl;
}
方法三:重新分配,销毁整个双层vector释放
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<vector<int>> vec;
vec.push_back({1,2});
vec.push_back({4,5,6});
vec.push_back({7,8,9});
cout<<"vec outer size: "<<vec.size()<<endl;
for(const auto& i: vec){
cout <<"vec vinner size: "<<vec.size() <<" , vec inner capacity: "<<i.capacity()<<endl;
}
vector<std::vector<int>>().swap(vec);
cout<<"after releasing vec outer size: "<<vec.size()<<endl;
}
上面三种方法运行结果如图:
5.多层vector释放内存
多层vector释放内存的顺序仍然遵循的基本原则:首先释放最深层的数据结构(内部对象),然后再释放上一层的对象,以此类推,直到释放最外层的对象。或者用vector<vector<vector<int>>>().swap(three_dim_vec);
#include <iostream>
#include <vector>
using namespace std;
void res(const vector<vector<vector<int>>>& tmp) {
cout << "最外层 vector size: " << tmp.size() << endl;
for (const auto& i : tmp) {
cout << "\中间层 vector size: " << i.size() << endl;
for (const auto& j : i) {
cout << "\t\t最内层 vector size: " << j.size() << endl;
}
}
}
int main() {
vector<vector<vector<int>>> vec;
for (int i = 0; i < 3; ++i) {
vector<vector<int>> vec1;
for (int j = 0; j < 2; ++j) {
vector<int> vec2;
for (int k = 0; k < 4; ++k) {
vec2.push_back(i * 100 + j * 10 + k);
}
vec1.push_back(vec2);
}
vec.push_back(vec1);
}
//三层vec
cout << "-----初始vec-----" << endl;
res(vec);
for (auto& vec1 : vec) {
for (auto& vec2 : vec1) {
vector<int>().swap(vec2); // 释放最深层
}
vector<vector<int>>().swap(vec1); // 释放中间层
}
vector<vector<vector<int>>>().swap(vec); // 释放最外层
// 打印释放内存后的向量信息
cout << "\n-----释放后vec-----" << endl;
res(vec); // 中间层和最内层不会输出,因为内存已经被释放,编译器可能报错
return 0;
}
运行结果如下:
更多推荐
所有评论(0)