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

How to delete an element of a vector through a getter function?

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

中的更新函数中

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

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 << "\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 它(即,在我们从仿函数 return true 之前)。

然后,容器在向量的开头包含所有有效元素,并保留顺序,在结尾包含所有无效元素。 remove_if returns 一个迭代器,指向无效元素开始的范围的开始。调用 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";
}