目录

内存分配

需要内存释放的场景

内存释放

1.清空vector的元素:clear()

2.【非强制】释放内存:clear() + shrink_to_fit()

3.【推荐】释放内存:swap()

4.双层vector释放内存

方法一:clear+shrink_to_fit释放

方法二:逐层采用swap释放

方法三:重新分配,销毁整个双层vector释放

5.多层vector释放内存


内存分配

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;
}

运行结果如下:

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐