tags:

views:

93

answers:

2

Let us assume we have a map class (unordered map, list, set, whatever will also do). We are looking for a specific element. After calling the find() member, we have to check with the end() member. But find() internally already knows whether it is returning a good iterator or the end iterator. Why should we need to call end() again? This adds some overhead.

std::map<int,float> myMap;
// some other code to populate the map
// ...
std::map<int,float>::iterator myIt;
myIt = myMap.find(2); // doesn't this already know wheter its returning the end() iterator?
if (myIt != myMap.end()) { //calling end() here wastes some time because find
                           //already knew the result
   std::cout << "Found, value is "<<(*myIt).second<<"\n";
} else {
   std::cout << "Not found.\n";
}

There should be a way to know what the result of find() is without calling end().

+6  A: 

What else could it possibly return? It needs to return a valid iterator, but anything other than end() would refer to an actual element in the container. There really isn't a choice here.

Also, STL functions such as end() are usually inline and on top of that compilers do a fair bit of optimization, so that extra call isn't really a call.

casablanca
While profiling one of my programs, I noticed that the end() call right after the find() call took 20% of the time of find(). So that is some 20% overhead. I understand conceptually find() returns a valid iterator, but isn't there a way to save on that 20% overhead?
highBandWidth
I was using GCC 4.2. Thanks for the -O2 and -O3 suggestions. I agree that this is small micro-performance and not needed in 99% of the cases.
highBandWidth
@user: Profiling without optimizations is completely meaningless.
FredOverflow
@user429850: I think these comments should have gone above, where the questions were asked. Anyhow, I don't know how you profiled your code but the 20% figure seems quite wrong.
casablanca
@Casablanca: I agree, they should have gone above. I was profiling with Shark on MacOSX.
highBandWidth
A: 

Alternatives are possible - for example, find() could return a std::pair or something akin to boost::optional - but there's little practical advantage and it requires an uglier, more error prone coding style. In languages (mainly interpreted) with an inbuilt None/null sentinel that's the ideal value for this, but C++ won't add that as there's a large cost in having a bool tagged on to every variable, and it's impractical to suddenly say "anyone wanting to store ints, listen up: -78 is hereafter reserved for end()/Null/whatever, please don't abuse it for other purposes". Container classes are in the best (only) place to know which value is an appropriate sentinel that wouldn't make sense as a legal iterator and allows a trivial, lightning fast != test, or if it's necessary to tack on that bool and use more complex iterator structures: end() abstracts that, and will be inlined in practice mitigating your performance concerns.

Tony