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() |
---|---|
元素的个数 | 实际分配的内存,不分配新空间的情况下,允许放入的最多元素数量 |
由此可以看到, 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() 的动作:开辟了新的更大的空间,移动了元素,销毁了原来的空间,并修改了指针
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,否则发生内存泄露