كيف يمكنني مسح reverse_iterator من stl بنية البيانات ؟
سؤال
لسبب البرمجية التالية يفشل.لا يمكنك ببساطة مسح 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
(أو وظيفة مثل ذلك).