万恶之源-vector
众所周知,vector会根据输入数据自动分配内部空间,无需人为指定大小,这当然方便我们日常使用,但自动分配也就意味着一定程度上的不可控,在某些情况下极易造成内存空间的浪费,比如下面这段代码:
vector<int>v;
for (int i = 0; i < 1000000; i++)
{
v.push_back(i);
}
这段代码的实际作用其实是向vector
容器中插入了100万个数,为了更加直观的展现vector
自动分配空间的坑,可以利用vector
的capacity()
成员函数可以返回它的实际存储空间大小 (自动开辟的空间),以及size()
返回容器中元素个数,在第一段代码之后输出vector容量:
vector<int>v;
for (int i = 0; i < 1000000; i++)
{
v.push_back(i);
}
cout << "v当前容量:" << v.capacity() << endl;
cout << "v当前大小:" << v.size() << endl;
运行结果为:
可以看到自动分配的空间与实际容量其实是相近的,在这种情况下并不存在空间浪费。
但是,如果在插入100万个元素之后,再使用resize()
成员函数,resize()
的作用是重新指定vector
大小,当重新指定的大小比原来的更大时,并不会造成内存浪费,但如果比原来的更小,情况就不一样了,来看下段代码演示:
vector<int>v;
for (int i = 0; i < 1000000; i++)
{
v.push_back(i);
}
cout &lt;&lt; "v当前容量:" &lt;&lt; v.capacity() &lt;&lt; endl;
cout &lt;&lt; "v当前大小:" &lt;&lt; v.size() &lt;&lt; endl;
cout &lt;&lt; "重新制定大小后:" &lt;&lt; endl;
v.resize(3); //重新指定大小
cout &lt;&lt; "v当前容量:" &lt;&lt; v.capacity() &lt;&lt; endl;//大小变小,容量不变
cout &lt;&lt; "v当前大小:" &lt;&lt; v.size() &lt;&lt; endl;</code></pre>
运行结果为:
你会发现resize()
虽然将vector
大小指定为了3,但实际占用空间还是原来的一百多万!这就造成了严重了内存空间浪费,甚至哪怕使用clear()
清空vector
,实际空间也不会发生任何变化!
<br />
内存救星-swap()
要想解决这个问题,其实不需要销毁vector
重新实例化,只需要利用自带的swap()
成员函数即可,swap()
的函数原型是void swap ( vector<T,Allocator>& vec );
作用就是交换两个vector,使用下面这段代码来实现内存空间收缩:
vector<int>v;
for (int i = 0; i < 1000000; i++)
{
v.push_back(i);
}
cout &amp;lt;&amp;lt; &quot;v当前容量:&quot; &amp;lt;&amp;lt; v.capacity() &amp;lt;&amp;lt; endl;
cout &amp;lt;&amp;lt; &quot;v当前大小:&quot; &amp;lt;&amp;lt; v.size() &amp;lt;&amp;lt; endl;
cout &amp;lt;&amp;lt; &quot;重新指定大小后:&quot; &amp;lt;&amp;lt; endl;
v.resize(3); //重新指定大小
cout &amp;lt;&amp;lt; &quot;v当前容量:&quot; &amp;lt;&amp;lt; v.capacity() &amp;lt;&amp;lt; endl;//大小变小,容量不变
cout &amp;lt;&amp;lt; &quot;v当前大小:&quot; &amp;lt;&amp;lt; v.size() &amp;lt;&amp;lt; endl;
vector&amp;lt;int&amp;gt;(v).swap(v);
cout &amp;lt;&amp;lt; &quot;利用swap()收缩内存空间后:&quot; &amp;lt;&amp;lt; endl;
cout &amp;lt;&amp;lt; &quot;v当前容量:&quot; &amp;lt;&amp;lt; v.capacity() &amp;lt;&amp;lt; endl;
cout &amp;lt;&amp;lt; &quot;v当前大小:&quot; &amp;lt;&amp;lt; v.size() &amp;lt;&amp;lt; endl;&lt;/code&gt;&lt;/pre&gt;
此时的运行结果:
<br />
浅扒一下底层
仔细观察下面这行代码:
vector&lt;int&gt;(v).swap(v);
这段代码"直译"过来就是:
-
新建了一个匿名的vector
-
将匿名vector与原vector交换(也就是实例化的v)
其实swap()
的底层原理就是将两个容器的指针互换(但迭代器指向未交换,切记!),将v
的指向从那"一百多万"的空间变成了新的匿名函数的"3"的空间,又因为匿名对象使用完就会被自动释放,因此也就把原vector
开辟的空间释放干净了,也就不存在内存浪费的问题了。
为方便理解,画个图演示下:
<br />
swap()的坑
虽然swap()
实现了两个容器指针互换,但并未交换其迭代器,也就是说:如果在swap()
之前就定义了迭代器,则交换后,虽然容器名的指向已经变了,但迭代器还是指向原内存空间,此时再对迭代器解引用将会得到错误的值,例如下段代码:
vector&lt;int&gt;v1 = { 1,2,3 };
auto it1 = v1.begin();
vector&amp;lt;int&amp;gt;v2 = { 4,5,6 };
auto it2 = v2.begin();
v1.swap(v2);
cout &amp;lt;&amp;lt; &quot;*it1=&quot; &amp;lt;&amp;lt; *it1 &amp;lt;&amp;lt; endl;
cout &amp;lt;&amp;lt; &quot;*it2=&quot; &amp;lt;&amp;lt; *it2 &amp;lt;&amp;lt; endl;&lt;/code&gt;&lt;/pre&gt;
实际运行结果为:
![file](data:image/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+)
&lt;br /&gt;
可以看到虽然已经执行了`swap()`函数,此时`v1`与`v2`的指向已经发生交换,但`it1`与`it2`还是指向原来的内存空间,此时对其解引用将无法得到正确的结果。
解决办法也很简单,在`swap()`交换后,重新给迭代器赋一下值,让它们更新到正确的地址,参考下段代码:
```cpp
vector&lt;int&gt;v1 = { 1,2,3 };
auto it1 = v1.begin();
vector&amp;lt;int&amp;gt;v2 = { 4,5,6 };
auto it2 = v2.begin();
v1.swap(v2);
//更新指向
it1 = v1.begin();
it2 = v2.begin();
cout &amp;lt;&amp;lt; &quot;*it1=&quot; &amp;lt;&amp;lt; *it1 &amp;lt;&amp;lt; endl;
cout &amp;lt;&amp;lt; &quot;*it2=&quot; &amp;lt;&amp;lt; *it2 &amp;lt;&amp;lt; endl;&lt;/code&gt;&lt;/pre&gt;
此时运行结果为:
![file](data:image/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+)
&lt;br /&gt;
*** ** * ** ***
&gt; 参考文章:https://blog.csdn.net/qq_43684922/article/details/96569413
&gt;
&gt;
```