我是C ++的新手,我正在使用Singleton设计模式和各种状态机进行游戏。目前,我的大多数游戏都在我的Engine类更新函数中更新信息,并且我需要移动大部分代码转到我的gamestate类中的Update函数。
我需要移动的某些代码可以管理和删除敌人向量中的敌人,如下所示。由于我正在访问类之外的某些向量,因此我在下面使用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
中删除该项目。[找到要删除的项目时:
delete
分配的内存- 减少循环变量。在下一个循环迭代中,您要检查占用相同内存地址的新项
- 获取标识当前项目的适当类型的迭代器
- 调用
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
在容器的每个项目上应用谓词,如果满足条件,则将该项目移动到容器的末尾(可能会使其数据无效)。由于指针在将其移到容器的末尾后可能会失效,因此我们需要在移动之前(即,从函子返回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 << "\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"; }