Вы удаляете объект, на который указывает m_vEnemies[i]
, и устанавливаете m_vEnemies[i]
на nullptr
, но в следующий раз, когда вы выполните итерацию по массиву, этот nullptr
все еще там, и вы попытаетесь разыменовать его , Вам также необходимо erase
элемент из вектора. Элементы удаляются из векторов с помощью итераторов.
Однако вы не можете просто выполнить итерацию по вектору с использованием стандартной семантики for (auto it = v.begin(); it != v.end(); it++)
и стереть элемент в середине l oop, поскольку стираете элемент из vector
делает недействительными его итераторы.
Хитрость заключается в том, чтобы войти в итератор для удаляемого элемента, используя
std::vector<T *>::iterator erase_iterator = v.begin() + i;
, который затем можно использовать для удаления элемента из vector
после соответствующего удаления.
Когда вы найдете объект, который хотите удалить, вы:
delete
выделенная память - Уменьшите ваш l oop переменная. На следующей итерации l oop вы хотите проверить новый элемент, который занимает этот же адрес памяти
- Получить итератор соответствующего типа, который идентифицирует текущий элемент
- Вызов
std::vector::erase(iterator)
стереть элемент из вектора.
Не то чтобы это вызывало изменение всех указателей в векторе, поскольку элементы хранятся в массиве непрерывно.
#include <iostream>
#include <vector>
void print_container_info(std::vector<int *>& container)
{
std::cout << "Container size: " << container.size() << "\n";
std::cout << "Container contents: ";
for (auto& item : container)
{
std::cout << *item << " ";
}
}
int main(int argc, char** argv)
{
std::vector<int*> p_int_vec = { new int(3), new int(1), new int(2), new int(2), new int(3), new int(3), new int(2) };
print_container_info(p_int_vec);
std::cout << "\n\n";
std::cout << "Removing all elements equal to 2 using for loop\n";
for (std::size_t i = 0; i < p_int_vec.size(); i++)
{
if (*p_int_vec[i] == 2)
{
auto erase_iterator = p_int_vec.begin() + i;
delete p_int_vec[i];
p_int_vec.erase(erase_iterator); //no need to set to nullptr, we're removing it from the container
--i; // must decrement
}
}
print_container_info(p_int_vec);
std::cout << "\n\n";
}
Вы можете также включите библиотеку algorithm
и используйте функцию std::remove_if
. remove_if
применяет предикат к каждому элементу контейнера и перемещает элемент в конец контейнера (потенциально лишает законной силы его данные), если критерий удовлетворен. Поскольку указатель может быть недействительным после перемещения его в конец контейнера, нам нужно delete
его перед перемещением (т. Е. Прежде чем мы вернем true из функтора).
Затем контейнер содержит все допустимые элементы в начале вектора с сохранением порядка и все недействительные элементы в конце. remove_if
возвращает итератор в начало диапазона, в котором начинаются недействительные элементы. После вызова remove_if
, вы должны вызвать std::erase
в диапазоне между этим итератором и окончанием контейнера.
#include <iostream>
#include <vector>
#include <algorithm>
void print_container_info(std::vector<int *>& container)
{
std::cout << "Container size: " << container.size() << "\n";
std::cout << "Container contents: ";
for (auto& item : container)
{
std::cout << *item << " ";
}
}
int main(int argc, char** argv)
{
std::vector<int*> p_int_vec = { new int(3), new int(1), new int(2), new int(2), new int(3), new int(3), new int(2) };
print_container_info(p_int_vec);
std::cout << "\n\n";
std::cout << "Removing all elements equal to 2 using for loop\n";
auto dummy_begin = std::remove_if(p_int_vec.begin(), p_int_vec.end(),
[](int* p_int) {
if (*p_int == 2)
{
delete p_int;
return true;
}
return false;
});
p_int_vec.erase(dummy_begin, p_int_vec.end());
print_container_info(p_int_vec);
std::cout << "\n\n";
}