C STL:由于迭代器和reverse_iterator缺少基类而复制代码

前端之家收集整理的这篇文章主要介绍了C STL:由于迭代器和reverse_iterator缺少基类而复制代码前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在我当前的C -project中,我有一个STL映射,它将整数键映射到对象上.算法返回一组条目.返回的数据取决于算法的输入,因此无法预测:
  1. class MyClass
  2. {
  3. //...
  4. };
  5.  
  6. int myAlgorithm(vector<int>::iterator inputIt)
  7. {
  8. // return a key for myMap which is calculated by the current value of inputData
  9. }
  10.  
  11. int main(int argc,char *argv[])
  12. {
  13. vector<int> inputData;
  14. map<int,MyClass> myMap;
  15. //<fill map with some data>
  16. //<fill inputData>
  17.  
  18. vector<MyClass> result;
  19.  
  20. for (vector<int>::iterator it = inputData.begin(); it != inputData.end(); it++)
  21. {
  22. int myMapKey = myAlgorithm(*it);
  23. // count() > 0 means "check whether element exists. Performance can be improved by replacing
  24. // the operator[] and count() calls by map::find(). However,I want to simplify things
  25. // in this example.
  26. if (myMap.count(myMapKey) > 0)
  27. {
  28. // in some cases there is no entry in myMap
  29. result.push_back(myMap[myMapKey]);
  30. }
  31. }
  32. }

如示例中所述,我可以使用find替换map :: count()和operator []. STL-reference表示map :: find()的复杂度在大小上是对数的(O(log n)).

我发现在大多数情况下,myMap中的条目非常接近结果中的两个后续条目.因此,我得出的结论是,如果我用迭代器替换map.find()调用,我会获得更好的性能

  1. map<int,MyClass>::iterator myMapIt = myMap.begin();
  2. for (vector<int>::iterator it = inputData.begin(); it != inputData.end(); it++)
  3. {
  4. int myMapKey = myAlgorithm(*it);
  5. // just increment iterator
  6. while (myMapKey != myMapIt->first)
  7. {
  8. myMapIt++;
  9. // we didn't find anything for the current input data
  10. if (myMapIt == myMap::end() || myMapIt->first > myMapKey)
  11. {
  12. break;
  13. }
  14. }
  15.  
  16. // I know that I'm checking this twice,but that's not the point of my
  17. // question ;)
  18. if (myMapIt == myMap::end() || myMapIt->first > myMapKey)
  19. {
  20. // probably it would be better to move the iterator back to the position
  21. // where we started searching,to improve performance for the next entry
  22. myMapIt = myMap.begin();
  23. }
  24. else
  25. {
  26. result.push_back(myMapIt.second);
  27. }
  28. }

这个概念有效,但我有一个大问题:根据inputData,我必须向前或向后搜索.考虑我多次调用main()中的代码,并且这些调用的inputData发生了变化.而不是检查是否增加或减少while循环内的迭代器,我可以在进入for循环之前决定.

我认为我只需将地图<> :: iterator切换为map<> :: reverse_iterator并使用rbegin()/ rend()而不是begin()/ end().但后来我意识到reverse_iterator和iterator没有共同的基类:

  1. map<int,MyClass>::base_iterator myIt;
  2. if (/* ... */)
  3. {
  4. myMapIt = myMap::begin();
  5. myMapEndIt = myMap::end();
  6. }
  7. else
  8. {
  9. myMapIt = myMap::rbegin();
  10. myMapEndIt = myMap::rend();
  11. }
  12. /* for (...) ... */

那会很棒,但是没有base_iterator.

我知道这个问题的一个简单的解决方法:我只需要复制整个for循环并针对这两种情况进行调整:

  1. if (/* ... */)
  2. {
  3. /* for(...) which uses normal iterator in the while-loop */
  4. }
  5. else
  6. {
  7. /* for(...) which uses reverse iterator in the while-loop */
  8. }

很糟糕……你知道一个更好的解决方案吗?

解决方法

当语言允许通用编程时,不需要通用基本类型.

你需要意识到的是,你可以拥有几个嵌套函数,其中每个选项都会导致不同的调用,而不是一个冗长的线性函数,并且有多个选择.

举个例子:

  1. boost::any_iterator start,end;
  2. if (/* ... */) {
  3. start = map.begin(),end = map.end();
  4. } else {
  5. start = map.rbegin(),end = map.rend();
  6. }
  7.  
  8. // do something with start and end

您可以将代码转换为以下内容

  1. // Define a free-function in the .cpp to help factor common stuff
  2. template <typename FwdIt>
  3. static void dosomething(FwdIt start,FwdIt end) {
  4. // do something with start and end
  5. }

然后将调用直接注入if / else主体:

  1. if (/* ... */) {
  2. dosomething(map.begin(),map.end());
  3. } else {
  4. dosomething(map.rbegin(),map.rend());
  5. }

一个好处是,您可以减少函数中状态的更改次数,从而减少其复杂性.

猜你在找的C&C++相关文章