ما هي أنظف طريقة المشي وunwalk والأمراض المنقولة جنسيا :: ناقلات باستخدام التكرارات؟

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();
    }
  }
}

وفي ظل ظروف طبيعية - على افتراض كل شيء على ما يرام - I مسيرة على طول الطريق إلى my_list.end() ووضع حد لحلقة بنجاح

ولكن، إذا كان هناك شيء يذهب على نحو خاطئ بينما أنا أفعل الاشياء، وأريد أن أكون قادرا على التراجع عن كل شيء - في الأساس نسترجع خطواتي العودة إلى البدايات الأولى للناقلات، التراجع عن كل شيء في وقت واحد في ترتيب عكسي

ومشكلتي هي أنني عندما نصل الى my_list.begin() - كما هو مبين في متداخلة للحلقة - أنا حقا لم تفعل حتى الآن لأنني لا تزال بحاجة إلى استدعاء undoStuff() على العنصر الأول لي في القائمة. الآن، أنا فقط يمكن إجراء المكالمة الأخيرة خارج من الحلقة، ولكن هذا يبدو متسخا قليلا.

والطريقة التي أرى ذلك، وأنا انتهيت فقط عندما أحصل على my_list.rend(). ومع ذلك، لا يمكن مقارنة الأمراض المنقولة جنسيا :: ناقلات :: مكرر إلى الأمراض المنقولة جنسيا :: ناقلات :: reverse_iterator.

وبالنظر إلى ما أحاول القيام به، وما هو أفضل خيار مكرر من نوع مزيج / حلقة؟

هل كانت مفيدة؟

المحلول

وأثناء استخدام التكرارات العكسية عبر rbegin() وrend() يعمل بشكل جيد، للأسف أجد أن تحويل بين عكس وغير عكس iterarotrs يميل إلى أن يكون مربكا للغاية. أنا لا يمكن أبدا أن نتذكر دون الحاجة إلى الذهاب من خلال ممارسة منطق لغز ما إذا كنت بحاجة إلى زيادة أو إنقاص قبل أو بعد عملية التحويل. ونتيجة لذلك أنا عموما تجنب التحويل.

إليك الطريقة كنت على الارجح التعليمات البرمجية حلقة معالجة الأخطاء. علما بأنني كنت تعتقد أنك لن تضطر إلى استدعاء 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()));
}

ويمكن أن يتم ذلك مع 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