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

问题描述 投票:-1回答:1

我是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;

        }
    }
c++ singleton sdl state-machine
1个回答
0
投票
您正在删除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分配的内存
  1. 减少循环变量。在下一个循环迭代中,您要检查占用相同内存地址的新项
  2. 获取标识当前项目的适当类型的迭代器
  3. 调用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"; }

  • © www.soinside.com 2019 - 2024. All rights reserved.