问题实例
我们习惯了STL容器的自动扩张,因此可能会写下一些愚蠢的程序,举例而言:1
2
3
4
5
6int transmogrify(int x);//产生一个自变量是x的因变量
vector<int> values;
... // 把数据放入values
vector<int> results;
//对values中的所有元素使用函数,将结果插入res尾部
transform(values.begin(), values.end(),results.end(),transmogrify);
在本例中,transform调用了*res.end(),也就是说我们试图对一个不存在的对象赋值。
解决方案
插入迭代器
插入于结尾处
transform的结果放入结尾应该使用back_inserter来产生指向res末尾的迭代器:1
2vector<int> results;
transform(values.begin(), values.end(), back_inserter(results), transmogrify);
插入于最前端
如果你试图在最前端插入,当然可以用front_inserter,只是这样支持的容器只剩了list与deque.
如果依次添加到最前面,那么最终顺序与values对应的顺序不一致(正好相反),解决方法也简单,调用反向迭代器即可:1
2list<int> results;
transform(values.rbegin(), values.rend(),front_inserter(results), transmogrify);
在任意位置插入
inserter迭代器允许你强制算法把结果插入在任何位置:1
2vector<int> results;// results已经有一些数据
transform(values.begin(), values.end(), inserter(results, results.begin()+results.size()/2), transmogrify);
提高效率
每一次都只插入了一个对象,因此可能会造成线性表频繁的复制与扩容。对于复制没有什么优化思路,但至少可以使用reserve来减少再分配所带来的开销:1
2
3
4
5
6
7vector<int> values;
vector<int> results;
...
results.reserve(results.size() + values.size());
transform(values.begin(), values.end(),
inserter(results, results.begin() + results.size() / 2),
transmogrify); //无需扩容
替换而非插入
有时候我们要做的操作并不是插入而是替换,但这并不影响我们是否需要判断results的大小,解决方法要么resize,要么clear之后使用插入迭代器:1
2
3
4
5
6
7
8
9//resize法
if (results.size() < values.size()){ //确保大小
results.resize(values.size());
}
transform(values.begin(), values.end(),results.begin(), transmogrify);
//clear之后插入
results.clear();
results.reserve(values.size()); // 扩容优化
transform(values.begin(), values.end(),back_inserter(results),transmogrify);
总结
当我们使用一个要求指定目的区间的算法时,务必要确保目的区间已经足够大或者在算法执行时可以增加大小。如果需要增加大小,记得使用插入迭代器。