Search code examples
c++puzzlefencepost

How could this code behave as I saw?


I have a C++ application that had a one time assertion failure that I cannot reproduce. Here is the code that failed once:

unsigned int test(std::vector<CAction> actionQueue) {
  unsigned int theLastCount = actionQueue.size() - 1;

  std::vector<CAction>::const_reverse_iterator rItr = actionQueue.rbegin();
  std::vector<CAction>::const_reverse_iterator rEndItr = actionQueue.rend();

  for (; rItr != rEndItr; ++rItr, --theLastCount) {
    const CAction &fileAction = *rItr;

    if (fileAction.test()) {
      continue;
    }
    return theLastCount;
  }

  assert(theLastCount == 0); // How could this fail?

  return theLastCount;
}

Somehow, theLastCount was not zero after the loop completed.

From my reading of the logic, this should be impossible unless:

  1. Some other thread side effected the actionQueue (which I don't think is possible).
  2. Some transient memory corruption occurred.

Am I missing something stupid here, is there a bug in my code shown? Note that in the occurrence where I saw this, theLastCount should have been initialized to one as the vector had two elements.


Solution

  • I believe that if test() passed for all fileActions, theLastCount would be -1. Consider:

    theLastCount starts at actionQueue.size() -1. You decrement it once for each item in actionQueue- that is, it is now actionQueue.size() - 1 - actionQueue.size() = -1. Think about it. theLastCount keeps the index of the current iterator. But when the current iterator is rend, then that is one iterator before the beginning of the array- which is -1.

    Edit: Oh, it's unsigned. But since you only test for equality to zero, then the integral overflow doesn't matter an awful lot here.