достоверность итератора после вызова Erase() в std::set

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

  •  06-07-2019
  •  | 
  •  

Вопрос

Вызов стирания в 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 будет компаратором.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top