достоверность итератора после вызова Erase() в std::set
Вопрос
Вызов стирания в std::set делает недействительным итератор?Как я сделал ниже 5-й от последней строки..?если да, то какой лучший способ стереть все элементы из набора
class classA
{
public:
classA(){};
~classA(){};
};
struct structB
{
};
typedef std::set <classA*, structB> SETTYPE;
typedef std::map <int, SETTYPE>MAPTYPE;
int __cdecl wmain (int argc, wchar_t* pArgs[])
{
MAPTYPE mapObj;
/*
...
.. Some Operation Here
...
*/
for (MAPTYPE::iterator itr1=mapObj.begin(); itr1!=mapObj.end(); itr1++)
{
SETTYPE li=(*itr1).second;
for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();itr2++)
{
classA *lt=(classA*)(*itr2);
li.erase(itr2);
delete lt; // Does it invalidate Iterator ?
}
}
}
Решение
Поскольку вы, очевидно, просто удаляете каждый элемент набора, вы можете просто сделать:
for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();itr2++)
{
classA *lt=(classA*)(*itr2);
delete lt;
}
li.clear(); // clear the elements
Другие советы
Из стандартного 23.1.2
Члены вставки не должны влиять на достоверность итераторов и ссылок на контейнер, а члены стирания должны делать недействительными только итераторы и ссылки на стертые элементы.
РЕДАКТИРОВАТЬ
В вашем случае itr2 становится недействительным после стирания, поэтому его увеличение приводит к неопределенному поведению.В этом случае вы можете последовать совету reko_t, в общем, можно попробовать так:
for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();)
{
classA *lt=(classA*)(*itr2);
li.erase(itr2++);
delete lt;
}
который увеличит итератор до удаление предыдущего значения из набора.
КСТАТИ.itr2 не аннулируется delete lt;
, но по li.erase(itr2);
Удаление в порядке.
Проблема в том, что вы стираете - и, таким образом, делаете недействительным - itr2
, но используйте его для итерации цикла.
и.а.в.после первого стирания ++itr2
имеет неопределенные результаты.
В этой ситуации я использую следующий шаблон:
while(itr2 != end())
{
iterator toDelete = itr2;
++itr2; // increment before erasing!
container.erase(toDelete);
}
Некоторые нестандартные реализации STL имеют функцию стирания, возвращающую следующий итератор, поэтому вы можете сделать:
while(itr2 != end())
itr2 = container.erase();
однако это не портативно.
тот set<A*,B>
является Однако странно - в стандартной реализации B будет компаратором.