vector 内存大小管理

news/2025/2/3 22:02:18/

vector 内存大小管理

环境: windows下 vs2019

1. size() 和 capacity()

1.1 定义一个空的 vector

vector<int> v;
cout << v.size() << endl;  //  0
cout << v.capacity() << endl;  // 0

空的 vector 的 size() 和 capacity() 都是 0

capacity() 的值应该受具体编译器的影响,只是在 vs2019 下等于 0,其它环境可能不为 0,但是size() 一定是 0

1.2 使用 reserve() 分配空间

reserve() 影响 capacity()

vector<int> v;v.reserve(10);
cout << v.size() << endl;            //0
cout << v.capacity() << endl;        //10

注意 reserve() 的空间是不能使用下标访问的

v[0] = 10;   // 会报错!!!

1.3 往 vector 中连续放入 5 个元素

使用push_back()

vector<int> v;v.reserve(10);v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);cout << v.size() << endl;           //5
cout << v.capacity() << endl;       //10
size()capacity()
元素的个数实际分配的内存,不分配新空间的情况下,允许放入的最多元素数量

"vector 内存示意图"

由此可以看到, reserve() 负责的是 capacity() 的大小

1.4 reserve() 只能增大 capacity() , 无法缩小 capacity()

尝试使用 reserve() 缩小 capacity()

vector<int> v;v.reserve(10);v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);v.reserve(8);
cout << v.size() << endl;           //5  
cout << v.capacity() << endl;       //10v.reserve(4);
cout << v.size() << endl;            //5 
cout << v.capacity() << endl;        //10

可以看到 vector 的内存大小不受影响

使用 reserve() 扩大 capacity()

vector 增大内存空间时,不是直接在原来内存的末尾增大空间,而是寻找新的空间,大小等于增大后的空间大小,然后将所有元素 移动 到新的空间,并销毁原来的空间

为验证元素被移动,这里打印 reserve() 前后 v[0] 的地址

vector<int> v;v.reserve(10);v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);cout << &v << endl;         //00AFFDA8
cout << &v[0] << endl;      //00E9E9E8
v.reserve(15);           
cout << v.size() << endl;     //5
cout << v.capacity() << endl; //15cout << &v << endl;       //00AFFDA8   
cout << &v[0] << endl;    //00E96C30

可以看到 capacity() 已经增大到 15,而且 v[0] 的地址确实发生改变了

注意 vector 这个对象本身的地址没有改变,因为 vector 本身的实现是个模板对象,里面存放了指针,依靠这些指针指向了 元素 的存储空间,我们改变的是 元素 的存储空间,只会影响到指针的值,对于封装了这些指针的 vector 本身而言,其在内存中的位置并没有发生改变

"reserve()增大内存"

reserve() 的动作:开辟了新的更大的空间,移动了元素,销毁了原来的空间,并修改了指针

1.5 向 vector 中插入元素

现在一直向 vector 中 push_back 元素,直到 size() == capacity() , 然后再 push_back 一个元素

vector<int> v;v.reserve(10);v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);v.reserve(15);cout << &v[0] << endl;  //0063F688
int k = 5;
// 放入元素,占满 v 的内存空间
while (v.size() != v.capacity())v.push_back(k++);cout << v.size() << endl;      //15
cout << v.capacity() << endl;  //15cout << &v[0] << endl;        //0063F688 未超出 capacity 之前,元素没有移动// 达到 capacity() 上限后再次 push_back 元素
v.push_back(k++);
cout << v.size() << endl;          //16
cout << v.capacity() << endl;      //22
cout << &v[0] << endl;             //006355C0    超出 capacity 后,元素发生移动,且capacity() 增大了很多,即预留了一些空间,给后续插入使用

所以 当插入的元素达到 capacity() 上限后,继续插入元素,就需要寻找新的更大的空间,发生元素移动,同时销毁原来的空间,并调整capacity() , 预留一些空间,capacity() 增大多少依赖于环境,这里从 15 变成了 22

如果继续增大超过 capacity()

vector<int> v;v.reserve(10);v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);v.reserve(15);int k = 5;
while (v.size() != v.capacity())v.push_back(k++);v.push_back(k++);
cout << v.size() << endl;          //16
cout << v.capacity() << endl;      //22while (v.size() != v.capacity())v.push_back(k++);
v.push_back(k++);
cout << v.size() << endl;           //23
cout << v.capacity() << endl;       //33

不清楚 capacity() 增大的量怎么计算的,反正就是增加了不少

C++ primer 是 将 capacity() 的值翻倍

1.6 shrink_to_fit()

shrink_to_fit() 将 capacity() 减小到 size() , 也就是回收了多分配而未使用的空间

vector<int> v;v.reserve(10);v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);v.reserve(15);int k = 5;
while (v.size() != v.capacity())v.push_back(k++);v.push_back(k++);while (v.size() != v.capacity())v.push_back(k++);
v.push_back(k++);
cout << v.size() << endl;      //23
cout << v.capacity() << endl;  //33v.shrink_to_fit();  // 回收多余未使用的空间
cout << v.size() << endl;       //23
cout << v.capacity() << endl;   //33

这里 v.shrink_to_fit() 回收了空间,现在 size() == capacity()

但是 C++ primer 中也说明 shrink_to_fit() 只是个请求,请求回收空间,这个回收请求也可能不被实现,所以内存也可能没有回收,要看具体环境

1.7 resize()

resize() 影响 size()

resize()reserve()
说明调整元素的个数 size()调整空间大小 capacity(),不会对已有的元素产生任何影响
区别1. 影响 size() ,既能增大 size(), 也能减小 size()
2. 如果增大后 size() 超过了 capacity(),就需要开辟新空间,移动元素,capacity() 的值也会增大。
3. 如果调整后 size() 不超过 capacity(), capacity() 就不受影响
4. 如果调整后的 size() 超过原来的元素数量,原来元素的值不发生变换,新增的值使用默认初始化或者由 size() 提供初始值
5. 如果调整后的 size() 小于原来元素的数量,只会将多余的元素去掉,且剩余的元素不发生任何变化,值保持不变,即使 size() 提供了初始值,也不会改变,size() 提供的初始值只会影响新增的值
影响 capacity(),且只能增大 capacity(), 无法减小 capacity()

resize (n, t)

n:调整后 size() 的大小,即调整 vector 元素的个数

t:如果 size() 增大了,用 t 初始化新增加的元素,如果 size() 减小了,t 没有作用;t 只对新增的值产生作用

​ t 是可选参数,没有 t 的话,新增的元素就使用默认初始化

// 重载 << , 输出 vector<int>
ostream& operator<< (ostream& os,vector<int>& v)
{for (auto& i : v)os << i << '\t';return os;
}vector<int> v;
v.reserve(10);v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);cout << v << endl;                      //0       1       2       3       4
cout << &v[0] << endl;                  // 013F9980
cout << v.size() << endl;               //5
cout << v.capacity() << endl << endl;   //10//将 v 的元素扩大到 8 个, 新增的元素使用默认初始化,即 0
v.resize(8);              
cout << v << endl;            //0       1       2       3       4       0       0       0
cout << &v[0] << endl;        //013F9980 没有开辟新空间,没有移动
cout << v.size() << endl;     //8
cout << v.capacity() << endl<<endl;  //10//将 v 的元素缩小到 3 个,数量减小, 参数 11 不起作用
v.resize(3,11);
cout << v << endl;            //0       1       2
cout << &v[0] << endl;        //013F9980 没有开辟新空间,没有移动
cout << v.size() << endl;     //3
cout << v.capacity() << endl<<endl;  //10//将 v 的元素扩大到 6 个, 新增的元素使用置为222
v.resize(6,222);
cout << v << endl;         //0       1       2       222     222     222
cout << &v[0] << endl;     //013F9980 没有开辟新空间,没有移动
cout << v.size() << endl;  //6
cout << v.capacity() << endl<<endl; //10 //将 v 的元素扩大到 22 个, 新增的元素使用置为333
v.resize(20, 333);
cout << v << endl;   //0       1       2       222     222     222     333     333     333     333     333     333     333     333     333    333      333     333     333     333
cout << &v[0] << endl;       //013F4678 开辟新空间,元素移动
cout << v.size() << endl;    //20 
cout << v.capacity() << endl << endl;   //20

可以看到,当调整 size() 超过 capacity() 时,新空间的 capacity() == size(),并没有预留多的空间 , 而没有像 1.5 中那样把 capacity() 设置较大。

1.8 assign()

// 将 [first,last) 的元素依次放入 vector 中,直接覆盖了 vector 原来的所有元素
void assign(const_iterator first,const_iterator last);// 将 n 个 x 依次放入 vector 中,直接覆盖了 vector 原来的所有元素
void assign(size_type n,const T& x = T());

原来的元素都不要了,全部换成新的元素

示例1 { 1, 2, 3, 4, 5 }→ { 100, 200, 300 }

ostream& operator<<(ostream& os, vector<int>& v)
{for (auto& i : v)cout << i << '\t';return os;
}int main()
{vector<int> v = { 1,2,3,4,5 };cout << "原始 vector<int> " << endl;cout << v << endl;cout <<"size() = "<< v.size() << endl;cout<<"capacity() = " << v.capacity() << endl;/*原始 vector<int>1       2       3       4       5size() = 5capacity() = 5*/cout << endl << endl << endl;cout << "使用 assign 重新分配元素" << endl;v.assign({ 100,200,300 });cout << v << endl;cout <<"size() = " << v.size() << endl;cout <<"capacity() = " << v.capacity() << endl;/*使用 assign 重新分配元素100     200     300size() = 3capacity() = 5  */return 0;
}

示例2 { 9 }→ { 100, 200, 300 }

int main()
{vector<int> v = { 9 };cout << "原始 vector<int> " << endl;cout << v << endl;cout <<"size() = "<< v.size() << endl;cout<<"capacity() = " << v.capacity() << endl;/*原始 vector < int>9size() = 1capacity() = 1*/cout << endl << endl << endl;cout << "使用 assign 重新分配元素" << endl;v.assign({ 100,200,300 });cout << v << endl;cout <<"size() = " << v.size() << endl;cout <<"capacity() = " << v.capacity() << endl;/*使用 assign 重新分配元素100     200     300size() = 3capacity() = 3*/return 0;
}

示例3 { }→ { 100, 200, 300 }

int main()
{vector<int> v ;cout << "原始 vector<int> " << endl;cout << v << endl;cout <<"size() = "<< v.size() << endl;cout<<"capacity() = " << v.capacity() << endl;/*原始 vector<int>size() = 0capacity() = 0*/cout << endl << endl << endl;cout << "使用 assign 重新分配元素" << endl;v.assign({ 100,200,300 });cout << v << endl;cout <<"size() = " << v.size() << endl;cout <<"capacity() = " << v.capacity() << endl;/*使用 assign 重新分配元素100     200     300size() = 3capacity() = 3*/return 0;
}
resize()assign()
说明调整元素的个数 size()直接用新的元素覆盖原来的元素
区别1. 影响 size() ,既能增大 size(), 也能减小 size()
2. 如果增大后 size() 超过了 capacity(),就需要开辟新空间,移动元素,capacity() 的值也会增大, 但是 capacity() 没有预留更大的空间,而是 capacity() == size()。
3. 如果调整后 size() 不超过 capacity(), capacity() 就不受影响
4. 如果调整后的 size() 超过原来的元素数量,原来元素的值不发生变换,新增的值使用默认初始化或者由 size() 提供初始值
5. 如果调整后的 size() 小于原来元素的数量,只会将多余的元素去掉,且剩余的元素不发生任何变化,值保持不变,即使 size() 提供了初始值,也不会改变,size() 提供的初始值只会影响新增的值
1. 如果 assign() 需要的空间小于等于 capacity(), 不需要开辟新空间,只需要在原来的空间上重新分配元素即可,旧的元素都会被覆盖
2. 如果 assign() 需要的空间大于 capacity() ,那么可能需要开辟新的空间,也可能不用 (不清楚原因,好像直接在原来的空间后面续了一段空间,可能和具体内存情况有关,要是后面还有空间就直接用了,不需要全部重新分配),如果发生了重新分配内存,capacity() 也会被设置为更大的值,预留一定的空间

简化版本区别

resize()assign()
修改后元素数量 > 原始 capacity() >= 原始 size()发生新空间开辟,元素移动,旧空间销毁
新空间:size() ==capacity()
没有预留空间
旧元素值不变(已发生移动),新增元素默认初始化或者 使用提供的初始值初始化
可能发生新空间开辟,元素移动,旧空间销毁,也可能直接在原空间续一段空间
新空间:size() < capacity()
预留了一定空间
旧元素清空,全部替换成新元素
原始 capacity() > 修改后元素数量 > 原始 size()旧元素不变,新增元素默认初始化或者 使用提供的初始值初始化旧元素清空,全部替换成新元素
原始 capacity() > 原始 size() > 修改后元素数量只把多出来的部分删除,剩余旧元素不变旧元素清空,全部替换成新元素

2. vector clear() 清空元素

2.1 元素为普通内置类型, 如 int

// 重载 << , 输出 vector<int>
ostream& operator<< (ostream& os, vector<int>& v)
{for (auto& i : v)os << i << '\t';return os;
}vector<int> v;
v.reserve(10);v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);cout << v << endl;                      // 0       1       2       3       4
cout << &v[0] << endl;                  // 0080AE80
cout << v.size() << endl;               // 5
cout << v.capacity() << endl << endl;   // 10v.clear();cout << v << endl;                      // 无输出
cout << v.size() << endl;               // 0
cout << v.capacity() << endl << endl;   // 10

调用 clear() 之后, size() 为 0, 所有的元素都清空了, 但是 capacity() 保持不变, 也就是内存空间没有销毁

2.2 元素为类类型

由于 是 类类型,可以定义 类的 析构函数 ,当 vector 的 capacity() 不够时,需要开辟新空间,就会发生元素移动后 (拷贝构造函数),而在销毁旧空间的元素时,会调用 析构函数

2.2.1 push_back()


class base {friend ostream& operator<<(ostream& os, base& b);
private:int a = 1;string name;
public:base(string _name, int _a = 1) :name(_name), a(_a) { cout << name << "---" << a << "   construct" << endl; }base(const base& r):name(r.name),a(r.a) { cout<<name<<"---"<<a << "   copy()"<<endl; }  //拷贝构造//base(base&& r) :name(std::move(r.name)), a(std::move(r.a))  { cout << name << "---" << a << "   move()" << endl; }  // 移动构造~base() { cout << name << "---" << a << "   ~base()  "<< endl; }  // 析构函数};ostream& operator<<(ostream& os,base& b)
{os << b.name<<"---"<<b.a;return os;
}// 重载 << , 输出 vector<int>
ostream& operator<< (ostream& os, vector<base>& v)
{for (auto& i : v)os << i << '\t';return os;
}int main()
{vector<base> v;cout<<"原始 vector 的容量 : " << v.capacity() << endl;v.emplace_back("base", 1);cout << "插入第 1 个元素后, vector 的容量为 :" << v.capacity() << "   " << v << endl;/*原始 vector 的容量 : 0base---1   construct插入第 1 个元素后, vector 的容量为 :1   base---1*/cout << endl;cout << "尝试插入第 2 个元素" << endl;v.emplace_back("base", 2);cout << "插入第 2 个元素后, vector 的容量为 :" << v.capacity()<<"   "<<v << endl;/*尝试插入第 2 个元素base---2   constructbase---1   copy()base---1   ~base()插入第 2 个元素后, vector 的容量为 :2   base---1        base---2*/// 空间不够,发生了旧元素的拷贝,销毁cout << endl;cout << "尝试插入第 3 个元素" << endl;v.emplace_back("base", 3);cout << "插入第 3 个元素后, vector 的容量为 :" << v.capacity() << "   " << v << endl;/*尝试插入第 3 个元素base---3   constructbase---1   copy()base---2   copy()base---1   ~base()base---2   ~base()插入第 3 个元素后, vector 的容量为 :3   base---1        base---2        base---3*/// 空间不够,发生了旧元素的拷贝,销毁cout << endl;cout << "尝试插入第 4 个元素" << endl;v.emplace_back("base", 4);cout << "插入第 4 个元素后, vector 的容量为 :" << v.capacity() << "   " << v << endl;/*尝试插入第 4 个元素base---4   constructbase---1   copy()base---2   copy()base---3   copy()base---1   ~base()base---2   ~base()base---3   ~base()插入第 4 个元素后, vector 的容量为 :4   base---1        base---2        base---3        base---4*/// 空间不够,发生了旧元素的拷贝,销毁cout << endl;cout << "尝试插入第 5 个元素" << endl;v.emplace_back("base", 5);cout << "插入第 5 个元素后, vector 的容量为 :" << v.capacity() << "   " << v << endl;/*尝试插入第 5 个元素base---5   constructbase---1   copy()base---2   copy()base---3   copy()base---4   copy()base---1   ~base()base---2   ~base()base---3   ~base()base---4   ~base()插入第 5 个元素后, vector 的容量为 :6   base---1        base---2        base---3        base---4        base---5*/// 空间不够,发生了旧元素的拷贝,销毁cout << endl;cout << "尝试插入第 6 个元素" << endl;v.emplace_back("base", 6);cout << "插入第 6 个元素后, vector 的容量为 :" << v.capacity() << "   " << v << endl;/*尝试插入第 6 个元素base---6   construct插入第 6 个元素后, vector 的容量为 :6   base---1        base---2        base---3        base---4        base---5       base---6*/// 空间够,没有发生旧元素的拷贝,销毁cout << endl << "程序结束, 自动销毁 vector , 调用每个 元素 的 析构函数" << endl;/*程序结束, 自动销毁 vector , 调用每个 元素 的 析构函数base---1   ~base()base---2   ~base()base---3   ~base()base---4   ~base()base---5   ~base()base---6   ~base()*/return 0;
}

输出如下:

原始 vector 的容量 : 0
base---1   construct
插入第 1 个元素后, vector 的容量为 :1   base---1尝试插入第 2 个元素
base---2   construct
base---1   copy()
base---1   ~base()
插入第 2 个元素后, vector 的容量为 :2   base---1        base---2尝试插入第 3 个元素
base---3   construct
base---1   copy()
base---2   copy()
base---1   ~base()
base---2   ~base()
插入第 3 个元素后, vector 的容量为 :3   base---1        base---2        base---3尝试插入第 4 个元素
base---4   construct
base---1   copy()
base---2   copy()
base---3   copy()
base---1   ~base()
base---2   ~base()
base---3   ~base()
插入第 4 个元素后, vector 的容量为 :4   base---1        base---2        base---3        base---4尝试插入第 5 个元素
base---5   construct
base---1   copy()
base---2   copy()
base---3   copy()
base---4   copy()
base---1   ~base()
base---2   ~base()
base---3   ~base()
base---4   ~base()
插入第 5 个元素后, vector 的容量为 :6   base---1        base---2        base---3        base---4        base---5尝试插入第 6 个元素
base---6   construct
插入第 6 个元素后, vector 的容量为 :6   base---1        base---2        base---3        base---4        base---5       base---6程序结束, 自动销毁 vector , 调用每个 元素 的 析构函数
base---1   ~base()
base---2   ~base()
base---3   ~base()
base---4   ~base()
base---5   ~base()
base---6   ~base()

注意使用 emplace_back () ,直接在 vector 的空间中构造对象, 如果 是 push_back,会先构造 临时对象, 然后把临时对象复制到 vector 的空间,随后立刻销毁 临时对象,这样临时对象会 产生一次 构造函数 和 析构函数。

2.2.2 emplace_back()

现在使用 使用 push_back() 代替 emplace_back()

vector<base> v;cout<<"原始 vector 的容量 : " << v.capacity() << endl;//v.emplace_back("base", 1);
v.push_back({ "base", 1 });
cout << "插入第 1 个元素后, vector 的容量为 :" << v.capacity() << "   " << v << endl;/*原始 vector 的容量 : 0base---1   constructbase---1   copy()base---1   ~base()插入第 1 个元素后, vector 的容量为 :1   base---1
*/// 发生临时对象(base1)的构造,拷贝,销毁cout << endl;
cout << "尝试插入第 2 个元素" << endl;
//v.emplace_back("base", 2);
v.push_back({ "base", 2 });
cout << "插入第 2 个元素后, vector 的容量为 :" << v.capacity()<<"   "<<v << endl;/*尝试插入第 2 个元素base---2   constructbase---2   copy()base---1   copy()base---1   ~base()base---2   ~base()插入第 2 个元素后, vector 的容量为 :2   base---1        base---2
*/// 发生临时对象(base2)的构造,拷贝,销毁, 原始空间不够,发生了旧元素的拷贝,销毁cout << endl;
cout << "尝试插入第 3 个元素" << endl;
//v.emplace_back("base", 3);
v.push_back({ "base", 3 });
cout << "插入第 3 个元素后, vector 的容量为 :" << v.capacity() << "   " << v << endl;
/*尝试插入第 3 个元素base---3   constructbase---3   copy()base---1   copy()base---2   copy()base---1   ~base()base---2   ~base()base---3   ~base()插入第 3 个元素后, vector 的容量为 :3   base---1        base---2        base---3
*/
// 发生临时对象(base3)的构造,拷贝,销毁, 原始空间不够,发生了旧元素的拷贝,销毁cout << endl;
cout << "尝试插入第 4 个元素" << endl;
//v.emplace_back("base", 4);
v.push_back({ "base", 4 });
cout << "插入第 4 个元素后, vector 的容量为 :" << v.capacity() << "   " << v << endl;
/*尝试插入第 4 个元素base---4   constructbase---4   copy()base---1   copy()base---2   copy()base---3   copy()base---1   ~base()base---2   ~base()base---3   ~base()base---4   ~base()插入第 4 个元素后, vector 的容量为 :4   base---1        base---2        base---3        base---4
*/
// 发生临时对象(base4)的构造,拷贝,销毁, 原始空间不够,发生了旧元素的拷贝,销毁cout << endl;
cout << "尝试插入第 5 个元素" << endl;
//v.emplace_back("base", 5);
v.push_back({ "base", 5 });
cout << "插入第 5 个元素后, vector 的容量为 :" << v.capacity() << "   " << v << endl;
/*尝试插入第 5 个元素base---5   constructbase---5   copy()base---1   copy()base---2   copy()base---3   copy()base---4   copy()base---1   ~base()base---2   ~base()base---3   ~base()base---4   ~base()base---5   ~base()插入第 5 个元素后, vector 的容量为 :6   base---1        base---2        base---3        base---4        base---5
*/
// 发生临时对象(base6)的构造,拷贝,销毁, 原始空间不够,发生了旧元素的拷贝,销毁cout << endl;
cout << "尝试插入第 6 个元素" << endl;
//v.emplace_back("base", 6);
v.push_back({ "base", 6 });
cout << "插入第 6 个元素后, vector 的容量为 :" << v.capacity() << "   " << v << endl;
/*尝试插入第 6 个元素base---6   constructbase---6   copy()base---6   ~base()插入第 6 个元素后, vector 的容量为 :6   base---1        base---2        base---3        base---4        base---5       base---6
*/cout << endl << "程序结束, 自动销毁 vector , 调用每个 元素 的 析构函数" << endl;
/*程序结束, 自动销毁 vector , 调用每个 元素 的 析构函数base---1   ~base()base---2   ~base()base---3   ~base()base---4   ~base()base---5   ~base()base---6   ~base()
*/

输出如下:

原始 vector 的容量 : 0
base---1   construct
base---1   copy()
base---1   ~base()
插入第 1 个元素后, vector 的容量为 :1   base---1尝试插入第 2 个元素
base---2   construct
base---2   copy()
base---1   copy()
base---1   ~base()
base---2   ~base()
插入第 2 个元素后, vector 的容量为 :2   base---1        base---2尝试插入第 3 个元素
base---3   construct
base---3   copy()
base---1   copy()
base---2   copy()
base---1   ~base()
base---2   ~base()
base---3   ~base()
插入第 3 个元素后, vector 的容量为 :3   base---1        base---2        base---3尝试插入第 4 个元素
base---4   construct
base---4   copy()
base---1   copy()
base---2   copy()
base---3   copy()
base---1   ~base()
base---2   ~base()
base---3   ~base()
base---4   ~base()
插入第 4 个元素后, vector 的容量为 :4   base---1        base---2        base---3        base---4尝试插入第 5 个元素
base---5   construct
base---5   copy()
base---1   copy()
base---2   copy()
base---3   copy()
base---4   copy()
base---1   ~base()
base---2   ~base()
base---3   ~base()
base---4   ~base()
base---5   ~base()
插入第 5 个元素后, vector 的容量为 :6   base---1        base---2        base---3        base---4        base---5尝试插入第 6 个元素
base---6   construct
base---6   copy()
base---6   ~base()
插入第 6 个元素后, vector 的容量为 :6   base---1        base---2        base---3        base---4        base---5       base---6程序结束, 自动销毁 vector , 调用每个 元素 的 析构函数
base---1   ~base()
base---2   ~base()
base---3   ~base()
base---4   ~base()
base---5   ~base()
base---6   ~base()

2.2.3 调用 clear()

使用 vector 保存 base 对象,调用 clear() 会自动销毁对象,自动调用 析构函数

class base {friend ostream& operator<<(ostream& os, base& b);
private:int a = 1;string name;
public:base(string _name, int _a = 1) :name(_name), a(_a) { cout << name << "---" << a << "   construct" << endl; }base(const base& r):name(r.name),a(r.a) { cout<<name<<"---"<<a << "   copy()"<<endl; }  //拷贝构造//base(base&& r) :name(std::move(r.name)), a(std::move(r.a))  { cout << name << "---" << a << "   move()" << endl; }  // 移动构造~base() { cout << name << "---" << a << "   ~base()  "<< endl; }  // 析构函数};int main()
{vector<base> v = { base("base",1), base("base",2), base("base",3) };/*base---1   constructbase---2   constructbase---3   constructbase---1   copy()base---2   copy()base---3   copy()base---3   ~base()base---2   ~base()base---1   ~base()*/// 此处仍然发生了临时对象的创建,拷贝销毁cout << "调用 clear()" << endl;v.clear();cout << "clear() 结束" << endl;/*调用 clear()base---1   ~base()base---2   ~base()base---3   ~base()clear() 结束*/// 调用 clear() 会自动调用对象的 析构函数return 0;
}

2.2.4 遗留个问题

在 vector 空间不足的时候,怎么使用移动构造,而非拷贝构造

2.3 元素类型为指针

当 vector 中的元素为 指针 时,在 clear() 之前如果不对指针进行 delete, 就会发生 内存泄露

2.3.1 vs2019 内存泄露检查

通过 new 动态申请空间,但是没有 delete

#include<iostream>
using namespace std;#define _CRTDBG_MAP_ALLOCint main()
{_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);int* p = new int(10);//delete p;return 0;
}

F5 调试后,在输出窗口检测到 内存泄露

Detected memory leaks!
Dumping objects ->
{152} normal block at 0x016965E0, 4 bytes long.Data: <    > 0A 00 00 00

重新设置 delete 后就不会有内存泄露

2.3.2 vector<int *>

使用 vector 保存 int 指针,调用 clear() 之前 没有 使用 delete p

int main()
{_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);vector<int*> v = { new int(1),new int(2),new int(3) };v.clear();return 0;
}

F5 调试后,在输出窗口检测到 内存泄露

{156} normal block at 0x00FC6680, 4 bytes long.Data: <    > 03 00 00 00 
{155} normal block at 0x00FC5E20, 4 bytes long.Data: <    > 02 00 00 00 
{154} normal block at 0x00FCEF80, 4 bytes long.Data: <    > 01 00 00 00

修改代码,clear() 前进行 delete 指针

int main()
{_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);vector<int*> v = { new int(1),new int(2),new int(3) };for (auto p : v)delete p;v.clear();return 0;
}

此时没有发生 内存泄露

2.3.3 vector<base*>

使用 vector 保存 base 指针,调用 clear() 之前 没有 使用 delete

#define _CRTDBG_MAP_ALLOCclass base {friend ostream& operator<<(ostream& os, base& b);
private:int a = 1;string name;
public:base(string _name, int _a = 1) :name(_name), a(_a) { cout << name << "---" << a << "   construct" << endl; }base(const base& r):name(r.name),a(r.a) { cout<<name<<"---"<<a << "   copy()"<<endl; }  //拷贝构造//base(base&& r) :name(std::move(r.name)), a(std::move(r.a))  { cout << name << "---" << a << "   move()" << endl; }  // 移动构造~base() { cout << name << "---" << a << "   ~base()  "<< endl; }  // 析构函数};int main()
{_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);vector<base*> v = { new base("base",1), new base("base",2), new base("base",3) };/*base---1   constructbase---2   constructbase---3   construct*/cout << "调用 clear()" << endl;v.clear();cout << "clear() 结束" << endl;/*调用 clear()clear() 结束*///没有调用 base 对象的 析构函数return 0;}

F5 调试后,在输出窗口检测到 内存泄露

Detected memory leaks!
Dumping objects ->
{200} normal block at 0x00BAF258, 8 bytes long.Data: <        > B4 0E BB 00 00 00 00 00 
{198} normal block at 0x00BB0EB0, 32 bytes long.Data: <    X   base    > 03 00 00 00 58 F2 BA 00 62 61 73 65 00 8B AE 00 
{195} normal block at 0x00BAF530, 8 bytes long.Data: <        > 94 10 BB 00 00 00 00 00 
{193} normal block at 0x00BB1090, 32 bytes long.Data: <    0   base    > 02 00 00 00 30 F5 BA 00 62 61 73 65 00 8B AE 00 
{156} normal block at 0x00BAEFF0, 8 bytes long.Data: < f      > 84 66 BA 00 00 00 00 00 
{154} normal block at 0x00BA6680, 32 bytes long.Data: <        base    > 01 00 00 00 F0 EF BA 00 62 61 73 65 00 8B AE 00 
Object dump complete.

修改代码,clear() 前进行 delete 指针

int main()
{_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);vector<base*> v = { new base("base",1), new base("base",2), new base("base",3) };/*base---1   constructbase---2   constructbase---3   construct*/cout<<"对 对象指针 进行 delete"<<endl;for (auto p : v)delete p;/*对 对象指针 进行 deletebase---1   ~base()base---2   ~base()base---3   ~base()*/cout << "调用 clear()" << endl;v.clear();cout << "clear() 结束" << endl;/*调用 clear()clear() 结束*/return 0;}

可以看到,对 base 对象指针进行 delete 时,调用了对象的析构函数,销毁了对象的空间

最后没有产生内存泄露

2.4 vector clear() 小结

元素为对象时,调用 clear() 会自动调用析构函数

元素为指针时,指针指向的对象无法析构,因此需要释放指针所指对象的话,需要在clear之前调用delete,否则发生内存泄露


http://www.ppmy.cn/news/334277.html

相关文章

git实操和理论知识

一、上传代码到gitlab中 1、安装git工具 yum install -y git2、准备要上传的代码 db Dockerfile LICENSE pom.xml README.md src3、初始化 git init Initialized empty Git repository in /etc/ssh/tomcat-java-demo-master/.git/4、添加远程仓库地址(复制要上传的代码库地…

5个接口性能提升的通用技巧

前言 作为后端开发人员&#xff0c;我们总是在编写各种API&#xff0c;无论是为前端web提供数据支持的HTTP REST API &#xff0c;还是提供内部使用的RPC API。这些API在服务初期可能表现不错&#xff0c;但随着用户数量的增长&#xff0c;一开始响应很快的API越来越慢&#x…

手机工作室网络如何组建?

现在很多的招商项目都是手机工作室的&#xff0c;包括做试玩、抖音还有做手游的&#xff0c;少则几十台手机&#xff0c;多则几百、上千台手机来做业务。 1. 组网问题 手机工作室很多人都会卡在组网上面&#xff0c;主要有三个问题&#xff1a; 1. 手机多了连不上WIFI&#…

这类开发者起薪30W,阿里腾讯华为抢着要......

(文末有惊喜) 前几天有个朋友在群里提问&#xff1a;如何看待大数据的未来&#xff1f;有必要转大数据方向吗&#xff1f; 关于这个问题&#xff0c;谈谈我的思考。伴随公有云厂商的兴起&#xff0c;大数据的应用进入了2.0时代。 传统大数据那种需要大量购买机器以及Hadoop发行…

基于Docker 部署gitlab-ce

1. 获取Gitlab镜像 1.1 查找Gitlab镜像 # 查找Gitlab镜像 $ sudo docker search gitlab-ce NAME DESCRIPTION STARS OFFICIAL AUTOMATED gitlab/gitlab-ce GitLab C…

解读CPU缓存,它们如何工作的?

究竟什么是 CPU 缓存&#xff1f;为什么有 L1、L2 和 L3 缓存&#xff1f;以下是您需要了解的内容以及它们的工作原理。 近年来&#xff0c;计算机中央处理器已经取得了相当大的进步&#xff0c;晶体管每年都在变小&#xff0c;性能也变得更加强大。每当提到处理器的性能时&am…

JVM调优命令、调优思路

文章目录 JVM调优工具jmap命令jstack命令查线程死锁查占有cpu资源 远程连接jvisualvmjinfo命令jstat垃圾回收统计堆内存统计新生代垃圾回收统计新生代内存统计老年代垃圾回收统计老年代内存统计元数据空间统计各内存区使用比例 JVM运行问题排查思路 JVM调优工具 jmap命令 主要…

卡牌游戏源代码(原创)(控制台)

游戏预览&#xff1a; 完成度90%&#xff0c;约3000行&#xff0c;过年这几天全用在这上面了 由于尚未学到QT等&#xff0c;因此只能在黑窗口下面制作了 未完成的部分&#xff1a; ①战斗代码未优化&#xff08;800行&#xff0c;精简后应该能降到200行左右&#xff09; ②关…