كيف يمكنني مسح reverse_iterator من stl بنية البيانات ؟

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

  •  03-07-2019
  •  | 
  •  

سؤال

لسبب البرمجية التالية يفشل.لا يمكنك ببساطة مسح reverse_iterator باستخدام قاعدة (طريقة).

#include <set>
#include <iostream>

int main()
{
    std::set<int> setOfInts;
    setOfInts.insert(1);
    setOfInts.insert(2);
    setOfInts.insert(3);

    std::set<int>::reverse_iterator rev_iter = setOfInts.rbegin();
    std::set<int>::reverse_iterator nextRevIter = setOfInts.rbegin();
    ++nextIter;

    while ( rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
        {
            // SEGFAULT HERE
            setOfInts.erase( rev_iter.base());
        }
        rev_iter = nextRevIter;
        ++nextRevIter;
    }

}

كيف دفعة واحدة حول القيام بشكل صحيح أعلاه ؟ نظرا reverse_iterator الذي يتوافق مع شيء كنت ترغب في مسح ، كيف يمكنك محو ذلك ؟

ملاحظة محو لن تأخذ reverse_iterators للأسف.يريد الشيء الحقيقي.

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

المحلول

يبدو أن الحل هو ما قاعدة() بإرجاع 1 قبالة.التالية الهوية يحمل على reverse_iterator:

&*(reverse_iterator(i)) == &*(i - 1) 

أو بعبارة أخرى ، reverse_iterator هو دائما واحدة تمر العادية التكرار هو قاعدة.لا يدري لماذا.

في دول مجلس التعاون الخليجي

ببساطة تغيير

        // SEGFAULT HERE
        setOfInts.erase( rev_iter.base());

إلى

        // WORKS!
        setOfInts.erase( --rev_iter.base());

أنا بالتأكيد غريبة على الرغم لماذا هوية أعلاه المنطقي.

في Visual Studio

العودة إلى العمل وتحاول هذا في visual studio أرى الحل أعلاه لا يعمل تماما.إن "nextIter" يصبح غير صالح على محو.بدلا من ذلك تحتاج إلى حفظ بعيدا مؤقتة من محو نحصل على التكرار بدلا من الاحتفاظ حول nextIter مثل أعلاه.

  set<int>::iterator tempIter = setOfInts.erase(--rev_iter.base());
  rev_iter = setOfInts.erase(tempIter);

لذلك الحل النهائي هو

int main()
{
    using namespace std;

    set<int> setOfInts;
    setOfInts.insert(1);
    setOfInts.insert(2);
    setOfInts.insert(3);

    set<int>::reverse_iterator rev_iter = setOfInts.rbegin();

    while ( rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
        {
            cout << "Erasing : " << *rev_iter;
            set<int>::iterator tempIter = setOfInts.erase( --rev_iter.base());
            rev_iter = set<int>::reverse_iterator(tempIter);            
        }
        else
        {
            ++rev_iter;
        }
    }   

}

ملاحظة النقابي حاويات لا عودة التكرار من محو.حتى هذا الحل لم يعمل على الخريطة ، multimap ، إلخ.

نصائح أخرى

عند تكرار مع عكس مكرر و ترغب في استخدام قاعدة() لتعديل الحاوية دائما نضع في اعتبارنا أن reverse_iterator دائما على أساس المقبل مكرر من النظام الأصلي.انها قليلا unintuitive ولكنه في الواقع يجعل رمز أبسط:

#include <set>
int main()
{
    std::set<int> setOfInts;
    setOfInts.insert(1);
    setOfInts.insert(2);
    setOfInts.insert(3);

    typedef std::set<int>::reverse_iterator RevIter;

    RevIter rev_iter = setOfInts.rbegin();
    while (rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
            setOfInts.erase(--rev_iter.base());

        ++rev_iter;
    }
}

في هذا المثال, ليست هناك حاجة للحفاظ على "التالي" مكرر منذ قاعدة التكرار لا يبطل!(نحن لا حاجة إليها عند التعامل مع التكرار العادي.)

سلوك عكس التكرار يخلق غريب خارج عن صعوبات عند التعامل مع عنصر واحد ولكن في حقائق هذا تبسيط نطاقات:

riValue = find(riEnd.base(), riBegin.base(), value);

يستخدم بالضبط نفس الأشياء (في ترتيب عكسي) كما

iValue = find(riBegin, riEnd, value);

1 من الخريطة::محو, نحن نعلم فإنه يأخذ فقط iterator;

2 من reverse_iterator::قاعدة, نحن نعرف &*(reverse_iterator ( i ) ) == &*( i – 1 ).

لذلك يمكنك مسح(--r_v.قاعدة()) لمحو عنصر أشار إلى "r_v" (و "الحالية-1"):

            r_v+1            r_v          r_v-1
           current-2      current-1      current

الاتصال erase مع التكرار نفسه (لا حاجة لاستخدام base).

#include <set>
#include <iostream>

int main()
{
    std::set<int> setOfInts;
    setOfInts.insert(1);
    setOfInts.insert(2);
    setOfInts.insert(3);

    std::set<int>::reverse_iterator rev_iter = setOfInts.rbegin();

    while (rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
        {
            rev_iter = setOfInts.erase(rev_iter);
        }
        else
        {
            ++rev_iter;
        }
    }
}

أيضا, أنت لا تحتاج إلى أن منفصل "التالي" مكرر (انظر التغييرات المذكورة أعلاه).أفضل طريقة للقيام بذلك هو استخدام std::remove_if (أو وظيفة مثل ذلك).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top