У меня есть вектор. Мне нужно удалить последние 3 элемента в нем. Описал эту логику. Программа вылетает. В чем может быть ошибка?
vector<float>::iterator d = X.end();
for (size_t i = 1; i < 3; i++) {
if (i == 1) X.erase(d);
else X.erase(d - i);
}
d
самом деле не существует. Это значение канарейки «один за другим» можно использовать только для того, чтобы найти конецvector
. Вы не можете удалить это. Далее, как только вы удалите итератор, он исчезнет. Вы не можете безопасно использовать его потом ни для чего, в том числеd - i
.Ответы:
Если в векторе есть хотя бы 3 элемента, удалить последние 3 элемента просто - просто используйте pop_back 3 раза:
Вывод:
источник
Это неопределенное поведение , чтобы передать
end()
итератор на 1-параметраerase()
перегрузки. Даже если это не так,erase()
аннулирует итераторы, которые находятся «в и после» указанного элемента, делаяd
недействительным после 1-й итерации цикла.std::vector
имеетerase()
перегрузку с двумя параметрами, которая принимает диапазон элементов для удаления. Вам не нужен ручной цикл вообще:Live Demo
источник
Во-первых,
X.end()
не возвращает итератор к последнему элементу вектора, он скорее возвращает итератор к элементу после последнего элемента вектора, который является элементом, которым вектор фактически не владеет, поэтому, когда вы пытаетесь стереть сX.erase(d)
помощью программы вылетает.Вместо этого, при условии, что вектор содержит как минимум 3 элемента, вы можете сделать следующее:
Который вместо этого идет к третьему последнему элементу и стирает каждый элемент после этого, пока не доберется до
X.end()
.РЕДАКТИРОВАТЬ: просто чтобы уточнить,
X.end()
это LegacyRandomAccessIterator, который указан, чтобы иметь допустимую-
операцию, которая возвращает другой LegacyRandomAccessIterator .источник
Определение
end()
из cppreference :и чуть ниже:
Другими словами, вектор не имеет элемента, на который указывает end (). По разыменованию , что не-элемент через метод стирания (), вы , возможно , изменяя память , которая не принадлежит к вектору. Отсюда могут происходить ужасные вещи.
Это обычное соглашение C ++ для описания интервалов как [low, high), с «низким» значением, включенным в интервал, и «высоким» значением, исключенным из интервала.
источник
Вы можете использовать
reverse_iterator
:Есть несколько вещей, чтобы упомянуть:
reverse_iterator rit
начинается с последнего элементаvector X
. Эта позиция называетсяrbegin
.erase
требует классикиiterator
для работы. Мы получаем это отrit
звонкаbase
. Но этот новый итератор будет указывать на следующий элементrit
в прямом направлении.rit
до вызоваbase
иerase
Также, если вы хотите узнать больше о
reverse_iterator
, я предлагаю посетить этот ответ .источник
Комментарий (теперь удаленный) в вопросе гласил, что «для итератора нет оператора». Тем не менее, следующий код компилируется и работает в обоих
MSVC
иclang-cl
, со стандартным набором либоC++17
илиC++14
:Ниже приводится определение
operator-
(в<vector>
заголовке):Тем не менее, я определенно не адвокат по языку C ++, и вполне возможно, что это одно из тех «опасных» расширений Microsoft. Мне было бы очень интересно узнать, работает ли это на других платформах / компиляторах.
источник
-
определены для этих типов итераторов.operator-
определено для итераторов, вы можете просто использоватьstd::advance()
илиstd::prev()
вместо.Это утверждение
имеет неопределенное поведение.
И это утверждение пытается удалить только элемент перед последним элементом
потому что у вас есть цикл только с двумя итерациями
Вам нужно что-то вроде следующего.
Выход программы
источник