2011-02-07 2 views
0

В документации list::erase() говорится: «вызов деструктора раньше», что это значит? Если я хочу, чтобы erase(it) вещь, а затем push_back(*it) элемент снова, будет ли это незаконным, так как он уже был разрушен?О C++ Метод класса списка STL erase()

+1

Вы уверены, что 'std :: list' является подходящим контейнером для вашего прецедента? Очень мало случаев использования, когда связанный список предлагает идеальные характеристики производительности. –

+1

@James McNellis. Основываясь на приведенном выше примере использования, похоже, что OP пытается перемещать элементы в списке. Это было бы довольно хорошим вариантом использования, так как все остальные последовательности принимают O (n), чтобы сделать это. – templatetypedef

+0

@templatetypedef: Возможно. Я все еще очень не решаюсь рекомендовать 'std :: list', не зная точно, как он используется. Размер каждого элемента, стоимость копирования каждого элемента, количество элементов и относительная частота сращивания против итерации являются важными критериями, и мы не знаем ни одной из этих вещей. –

ответ

5

Да, это приведет к неопределенному поведению. После того, как вы erase перечислите итератор вы invalidate итератор, что означает, что ссылающийся на него объект больше не будет считаться действительным. Это означает, что если вы попытаетесь использовать итератор в любом контексте, включая попытку разыменовать значение, чтобы добавить его в список снова, это приведет к неопределенному поведению, которое может привести к сбою программы, перезаписать важную память или ничего не делать.

Если вы хотите переместить элемент списка на спину, рассмотрите возможность использования splice метода, Лист:

myList.splice(myList.end(), myList, it); 

Это перемещает элемент в конец без создания копии.

+0

Не будет ли это сращивать намного больше, чем просто один элемент? Проверьте документацию. Вы правы, это будет правильно. – Omnifarious

+0

+1; Также метод, который я пропустил. См. Также версию, которая делает то же самое с рядом итераторов. – Keith

2

Элемент в контейнере разрушается, когда он удаляется из контейнера. Если вы хотите сохранить объект после его удаления из контейнера, вам нужно сделать его копию и вместо этого использовать копию.

Ваш предложенный код:

v.erase(it); 
v.push_back(*it); 

является недействительным, поскольку it аннулируется после стирания. Вы не можете использовать итератор после его недействительности.

0

Смешивание стирания и итераторов может быть очень сложным делом. Действительность различных итераторов после того, как вы сделали стирание, может варьировать форму контейнера в контейнере. То, что вам нужно сделать, если вы хотите сделать erase и push_back, это сохранить копию того, что находится в *it, а затем использовать копию, когда вы делаете push_back.

0

Элемент удаляется, уничтожая его, а затем удаляя ссылку на него из списка. Если вы хотите сохранить элемент, вам необходимо взять его копию перед вызовом стирания. Все это говорит о том, что, возможно, std :: list не является правильным контейнером для ваших нужд.