[CPP - STL] swap技巧
最近在看《Effective STL》,【条款17:使用“交换技巧”修整过剩容量】中提到容器的成函数void swap(container& from),即实现容器对象与from对象的交换。
另外,对于连续内存容器vector和string,还有shrink to fit(收缩到合适,根据容器的实际size设置capacity,减少实际内存分配)的功能。
以vector为例,首先说下,size和capacity、resize和reserve的含义及区别。
1. size和capacity、resize和reserve
size:对象的元素个数,除reserve外的几乎所有vector操作都可以影响size;
capacity:容器预留容量,即占用真实内存量,capacity >= size。push_back、insert、resize、reserve操作可以影响capacity,其特点为只增不减(即使erase和clear操作);
resize:可以改变size,如果resize的元素个数大于capacity,则同时改变capacity,增加对象内存空间;
reserve:不改变size,如果reserve的元素个数大于capacity,则改变capacity,增加对象内存空间,反之,则不影响capacity;
代码示例如下:
1 #include <iostream>
2 #include <vector>
3
4 using namespace std;
5
6 int main()
7 {
8 vector<int> v;
9 cout << "initial: " << endl;
10 cout << "size of v is " << v.size() << endl;
11 cout << "capacity of v is " << v.capacity() << endl << endl;
12
13 v.insert(v.end(), 10, 1);
14 cout << "after insert: " << endl;
15 cout << "size of v is " << v.size() << endl;
16 cout << "capacity of v is " << v.capacity() << endl << endl;
17
18 v.erase(v.end()-5, v.end());
19 cout << "after erase: " << endl;
20 cout << "size of v is " << v.size() << endl;
21 cout << "capacity of v is " << v.capacity() << endl << endl;
22
23 v.reserve(20);
24 cout << "after reserve: " << endl;
25 cout << "size of v is " << v.size() << endl;
26 cout << "capacity of v is " << v.capacity() << endl << endl;
27
28 v.resize(15);
29 cout << "after resize: " << endl;
30 cout << "size of v is " << v.size() << endl;
31 cout << "capacity of v is " << v.capacity() << endl << endl;
32
33 v.reserve(10);
34 cout << "after reserve: " << endl;
35 cout << "size of v is " << v.size() << endl;
36 cout << "capacity of v is " << v.capacity() << endl << endl;
37
38 v.clear();
39 cout << "after clear: " << endl;
40 cout << "size of v is " << v.size() << endl;
41 cout << "capacity of v is " << v.capacity() << endl << endl;
42
43 return 0;
44 }
输出结果为:
initial:
size of v is 0
capacity of v is 0
after insert:
size of v is 10
capacity of v is 10
after erase:
size of v is 5
capacity of v is 10
after reserve:
size of v is 5
capacity of v is 20
after resize:
size of v is 15
capacity of v is 20
after reserve:
size of v is 15
capacity of v is 20
after clear:
size of v is 0
capacity of v is 20
根据上面几个概念及Demo,可以看出来,vector对象的实际内存(即capacity)在多次insert和erase操作后大于实际元素个数(size),即使在clear操作后,capacity依然不会减小为零。
所以,有必要对这种基于内存池的容器做内存收缩。
2. swap:shrink to fit
修改vector对象多余内存空间的方法:
vector<int>(v).swap(v); // v为一个vector对象
vector<int>(v)基于v拷贝构造了一个临时vector,其分配了v.size()个元素的内存空间,即capacity为v.size(),然后vector<int>(v)与v交换数据,交换后,v的capacity也减少为v.size(),而临时vector对象vector<int>(v)被销毁。
另外,vector<int>().swap(v); // 可以清除v的内存空间
代码示例如下:
1 #include <iostream>
2 #include <vector>
3
4 using namespace std;
5
6 int main()
7 {
8 vector<int> v(10, 1);
9 cout << "initial: " << endl;
10 cout << "size of v is " << v.size() << endl;
11 cout << "capacity of v is " << v.capacity() << endl << endl;
12
13 v.erase(v.end()-5, v.end());
14 cout << "after erase: " << endl;
15 cout << "size of v is " << v.size() << endl;
16 cout << "capacity of v is " << v.capacity() << endl << endl;
17
18 vector<int>(v).swap(v);
19 cout << "after swap (shrink to fit): " << endl;
20 cout << "size of v is " << v.size() << endl;
21 cout << "capacity of v is " << v.capacity() << endl << endl;
22
23 vector<int>().swap(v);
24 cout << "after swap (clear): " << endl;
25 cout << "size of v is " << v.size() << endl;
26 cout << "capacity of v is " << v.capacity() << endl << endl;
27
28 return 0;
29 }
输出结果为:
initial:
size of v is 10
capacity of v is 10
after erase:
size of v is 5
capacity of v is 10
after swap (shrink to fit):
size of v is 5
capacity of v is 5
after swap (clear):
size of v is 0
capacity of v is 0
如果使用C++11及更新标准的话,可以直接使用shrink_to_fit函数。