如何通过 getter 函数删除矢量的元素?



我是C++新手,我正在开发一款使用单例设计模式和各种状态机的游戏。目前,我的大部分游戏更新信息都在引擎类更新函数中,我需要将大部分代码移动到游戏状态类的更新函数中。

我需要移动的一些代码管理和删除敌人向量中的敌人,如下所示。 由于我在类之外访问其中一些向量,因此我正在使用下面的 getter 函数。我正在尝试删除我的敌人,如果他们离开屏幕。但是,当敌人离开屏幕时,会抛出以下未处理的异常: _Mylast 0xDDDDDDE5。非常感谢可以提供的任何帮助。

for (int i = 0; i < (int)m_vEnemies.size(); i++)
{
m_vEnemies[i]->Update(); 
if (m_vEnemies[i]->GetDstP()->x < -56)
{
delete m_vEnemies[i];
m_vEnemies[i] = nullptr;
}
}
vector<Enemy*> Engine::getEnemies()
{
return m_vEnemies;
}
for (int i = 0; i < (int)Engine::Instance().getEnemies().size(); i++)
{
Engine::Instance().getEnemies()[i]->Update(); 
if (Engine::Instance().getEnemies()[i]->GetDstP()->x < -56)
{
delete Engine::Instance().getEnemies()[i];
Engine::Instance().getEnemies()[i] = nullptr;
}
}

您正在删除m_vEnemies[i]指向的对象并将m_vEnemies[i]设置为nullptr,但下次循环访问数组时,该nullptr仍然存在,您将尝试取消引用它。您还需要从矢量中erase项目。使用迭代器从矢量中删除项。

但是,您不能只使用标准for (auto it = v.begin(); it != v.end(); it++)语义遍历向量并在循环中间擦除项目,因为从vector中删除项目会使其迭代器失效。

诀窍是使用迭代器访问要删除的项目

std::vector<T *>::iterator erase_iterator = v.begin() + i;

然后,您可以使用它从适当删除项目后将其从vector中删除。

当您找到要删除的项目时:

  1. delete分配的内存
  2. 递减循环变量。在下一次循环迭代中,您要检查占用此相同内存地址的新项
  3. 获取标识当前项的适当类型的迭代器
  4. 调用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 << "nn";
std::cout << "Removing all elements equal to 2 using for loopn";
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 << "nn";
}

您还可以包含algorithm库,并使用std::remove_if函数。remove_if对容器的每个项应用谓词,并在满足条件时将该项移动到容器的末尾(可能会使其数据失效)。由于指针在移动到容器末尾后可能会失效,因此我们需要在移动之前(即,在从函子返回 true 之前)delete它。

然后,容器在向量的开头包含所有有效元素,保留顺序,并在末尾包含所有无效元素。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 << "nn";
std::cout << "Removing all elements equal to 2 using for loopn";
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 << "nn";
}

最新更新