Effective STL 学习笔记 Item 17: Swap Trick
假设有若干对象存于一个 vector 中:
class Widget; vector<Widget> vw;
后来由于某些原因,从该容器中删除了若干对象(参考erase-remove idiom )。对于 vector 和 string 来讲, erase() 和 clear() 并不会改变容器的capacity,也就不会改变他们的内存占用。
swap() 本意是用来交换两个容器的内容( Iterators, pointers, and references),但我们可以用他来快速将容器的 capacity 调整为 合适 的大小:
vector<Widget>(vw).swap(vw);
巧妙之处在于, vector 的拷贝构造函数仅仅拷贝有用的部分而忽略那些未占用的空间,用这个拷贝构造出来的容器来和 vw 进行 swap() 就可以调整 vw 的 capacity 为一个 相对较小的值 。
这里之所以说是 相对较小的值 而不是与 size() 绝对相等,是因为容器的 Implementation 在构造的时候会自己选取合适的值来保证分配的空间足够容纳所有的元素,但这个值可能会比 size() 大, 可参考Item 14 。
下面是一个简单的例子,对 vector 进行一些操作,然后输出其 erase, swap,clear 之后的 size 与 capacity:
#include <vector> #include <iostream> #include <time.h> #include <stdlib.h> #include <fstream> #include <iterator> using namespace std; const int MAX = 1024; #define show(v, msg) printf ("%s -- %s: size: %lu, capacity: %lu\n", \ #v, msg, v.size(), v.capacity()); int main(int argc, char *argv[]) { srand(time(NULL)); printf("Testing vector...\n"); vector<int> v; show(v, "After init"); v.reserve(MAX); show(v, "After reserve()"); for (int i = 0; i < MAX; ++i) { v.push_back(random()%1000); } show(v, "After Filling"); v.erase(remove_if(v.begin(), v.end(), [](int x){return x > 100;}), v.end()); show(v, "After erase()"); vector<int>(v).swap(v); show(v, "After swap()"); v.clear(); show(v, "after clear"); vector<int>().swap(v); show(v, "after swap with empty vector"); return 0; }
其输出如下:
Testing vector... v -- After init: size: 0, capacity: 0 v -- After reserve(): size: 0, capacity: 1024 v -- After Filling: size: 1024, capacity: 1024 v -- After erase(): size: 106, capacity: 1024 v -- After swap(): size: 106, capacity: 106 v -- after clear: size: 0, capacity: 106 v -- after swap with empty vector: size: 0, capacity: 0 Program ended with exit code: 0
(使用许可:署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议 。)