반복자를 사용하여 std :: 벡터를 걷고 걸어 다니는 가장 깨끗한 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/632805

문제

벡터를 통해 행진하고 일을하는 상황이 있습니다.

std::vector::iterator iter = my_list.begin();

for ( ; iter != my_list.end(); ++iter )
{
  if ( iter->doStuff() )   // returns true if successful, false o/w
  {
    // Keep going...
  }
  else
  {
    for ( ; iter != m_list.begin(); --iter )  // ...This won't work...
    {
      iter->undoStuff();
    }
  }
}

정상적인 조건에서 - 모든 것이 잘 진행된다고 가정하면 - 나는 끝까지 행진합니다. my_list.end() 루프를 성공적으로 끝내십시오.

그러나, 내가 일을하는 동안 무언가 잘못되면 모든 것을 취소 할 수 있기를 원합니다. 기본적으로 벡터의 시작 부분으로 내 단계를 되돌려 놓고 한 번에 하나씩 모든 것을 역 순서로 취소합니다.

내 문제는 내가 도착했을 때입니다 my_list.begin() - 루프를 위해 중첩 된대로 - 아직 전화해야하기 때문에 아직 완료되지 않았습니다. undoStuff() 목록의 첫 번째 요소에. 이제, 나는 루프 밖에서 최종 전화를 걸 수 있었지만 이것은 조금 부정한 것 같습니다.

내가 보는 방식, 나는 내가 도착했을 때만 끝났다 my_list.rend(). 그러나 std :: vector :: iterator를 std :: vector :: reverse_iterator와 비교할 수 없습니다.

내가하려는 일을 감안할 때, 반복자 유형 / 루프 조합의 최선의 선택은 무엇입니까?

도움이 되었습니까?

해결책

리버스 반복자를 통해 rbegin() 그리고 rend() 불행히도 잘 작동합니다. 불행히도 리버스와 리버스 이레라 로트 사이를 전환하는 것은 매우 혼란스러워하는 경향이 있습니다. 전환 전후에 득점 또는 감소가 필요한지 여부에 관계없이 논리 퍼즐 운동을하지 않아도 기억할 수 없습니다. 결과적으로 나는 일반적으로 변환을 피합니다.

오류 처리 루프를 코딩하는 방법은 다음과 같습니다. 당신이 전화 할 필요가 없다고 생각합니다. undoStuff() 실패한 반복자의 경우 - 결국 doStuff() 성공하지 못했다고 말했다.

// handle the situation where `doStuff() failed...

// presumably you don't need to `undoStuff()` for the iterator that failed
// if you do, I'd just add it right here before the loop:
//
//     iter->undoStuff();

while (iter != m_list.begin()) {
    --iter;
    iter->undoStuff();
}

다른 팁

STL 벡터에 관해서는 약간 녹슬었지만 std::vector::reverse_iterator 초기 반복자에서? 그러면 앞으로 나아갈 때 마지막으로했던 항목에서만 시작하면 my_list.rend() 첫 번째 항목이 처리되었는지 확인합니다.

물론 벡터를 사용하지 않을 이유가 없습니다. operator[]() 이것이 코드를 더 명확하고 단순하고 효율적으로 만드는 경우.

그것은 당신의 것에 달려 있습니다 doStuff() 기능은 당신의 맥락에서 성능이 얼마나 중요한지. 가능하다면 아마도 벡터 사본에서 작업하는 것이 더 명확해질 것입니다 (즉, 모든 것이 괜찮은 경우에만 벡터를 교환하십시오.

std::vector<Foo> workingCopy;
workingCopy.assign(myVector.begin(), myVector.end());

bool success = true;
auto iter = workingCopy.begin();
for( ; iter != workingCopy.end() && success == true; ++iter )
    success = iter->doStuff();

if( success )
    myVector.swap(workingCopy);

사용하지 않고 reverse_iterator, 당신은 이런 식으로 뒤로 걸을 수 있습니다 :

while(iter-- != m_list.begin())
{
    iter->undoStuff();
}

이것은 사본을 만듭니다 iter, 비용이 너무 크지 않아야합니다. 더 나은 속도를 위해 리팩터를 리팩터 할 수 있습니다.

while(iter != m_list.begin())
{
    --iter;
    iter->undoStuff();
}

가역적 반복기를 얻으려면 rbegin ()을 사용해야합니다.

개인적으로 나는 여전히 선호합니다

for (int i=0;i<vecter.size();i++) { }

좋아, 여기서 사지로 나갈 게 ..

std::vector iterator iter = my_list.begin();
bool error = false;

while(iter != my_list.end())
{
  error = !iter->doStuff();
  if(error)
    break
  else
    iter++;
}

if(error)
do
{
  iter->undoStuff();
  iter--;
} 
while(iter != my_list.begin())

이것이 제가 엔지니어링에 대해 부르는 것이지만 너무 재미 있습니다.

// This also can be done with adaptators I think
// Run DoStuff until it failed or the container is empty
template <typename Iterator>
Iterator DoMuchStuff(Iterator begin, Iterator end) {
  Iterator it = begin;
  for(; it != end; ++it) {
    if(!*it->DoStuff()) {
      return it;
    }
  }
  return it;
}

// This can be replaced by adaptators
template <typename Iterator>
void UndoMuchStuff(Iterator begin, Iterator end) {
  for(Iterator it = begin; it != end; ++it) {
    it->UndoStuff();
  }
}

// Now it is so much easier to read what we really want to do
typedef std::vector<MyObject*> MyList;
typedef MyList::iterator Iterator;
typedef MyList::reverse_iterator ReverseIterator;
Iterator it = DoMuchStuff(my_list.begin(), my_list.end());
if(it != my_list.end()) {
  // we need to unprocess [begin,it], ie including it
  UndoMuchStuff(ReverseIterator(1+it), ReverseIterator(my_list.begin()));
}

이것은 a로 수행 할 수 있습니다 reverse_iterator:

bool shouldUndo(false);
std::vector::iterator iter(my_list.begin()), end(my_list.end());
for ( ; iter != end && !shouldUndo; ++iter )
{
  shouldUndo = iter->doStuff();   // returns true if successful, false o/w
}
if (shouldUndo) {
  reverse_iterator<std::vector::iterator> riter(iter), rend(my_list.rend());
  //Does not call `undoStuff` on the object that failed to `doStuff`
  for ( ; riter != rend; ++riter )
  {
    iter->undoStuff();
  }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top