将一个向量的内容移动到另一个向量

Moving the contents of one vector to another

本文关键字:向量 移动 另一个 一个      更新时间:2023-10-16

所以我有一个向量:

vector<Enemy*> enemies;

这个矢量包含敌人,它们是在游戏中动态创建的。

if(rand() % 1000 > 998)
{
Enemy * enemy = new Enemy(num_of_enemies);
        enemies.push_back(enemy);
}

这个存在的问题是,即使敌人已经被删除,向量也会不断增长,这会减慢我的游戏速度。

本质上,我想把vector的内容移动到一个新的vector中,但只移动包含敌人的元素。

我读到有一个叫做std::move的东西,但我不确定如何正确地执行它,或者它是否会成功地移动包含敌人的元素,而不仅仅是整个向量。

任何帮助与代码实现结构将非常感激。

这是如何处理刷出和消灭敌人的完整工作流程。注意,这里根本没有指针。

  1. 生成敌人:

    if (if random_float_between_0_and_1() < 0.002)
        enemies.push_back(Enemy{arguments});
    
  2. 火的敌人;根据你下面的评论,应该看起来像这样:

    auto last_iter = std::remove_if(enemies.begin(), enemies.end(), is_dead);
    enemies.erase(last_iter, enemies.end());
    

    这里,is_dead是一个函数,它接受Enemy const&并确定它是否与玩家或屏幕边界碰撞:

    bool is_dead(Enemy const& enemy) {
        return outside_screen_area(enemy) or near_player(enemy);
    }
    

    函数outside_screen_areanear_player应该很容易实现。

    要理解上面的代码是如何工作的,请参阅std::removestd::vector::erase的文档

另一件事:根据c++ 11附带的标准库随机库实现random_float_between_0_and_1函数。不要在整数随机数上使用std::rand或取模运算,它们的效果很差(即它们不是真正均匀分布的,并且会给出倾斜的结果)。

这个存在的问题是,即使敌人已经被删除,向量也会不断增长…

实际上我想把向量的内容移动到一个新的向量…

在我看来,一种更简单的方法是从原始向量中删除指向已删除对象的指针,而不是创建一个副本。

指向不再存在的已删除对象的指针与指向已存在对象的指针没有区别。因此,必须跟踪必须从vector中删除的元素。最简单的解决方案是在元素被删除后立即删除它。使用智能指针,这变得容易得多,因为删除指针也会自动删除对象。

std::move不会帮你解决这个问题。

您可能想要考虑根本不使用手动动态分配。您可以将Enemy对象存储在vector中。

当要删除敌人时,我调用类析构函数,然后删除

delete表达式调用析构函数。你自己调用它也会有未定义的行为

首先,如果您想要删除随机位置的单个元素,我建议您不应该使用像std::vector这样的数据结构。该操作的复杂度与被删除元素后的元素个数线性
据我所知,你有许多敌人在2D屏幕上与一个(或多个)玩家肩并肩地移动。如果敌人被玩家击中或离开屏幕,它将被删除。你只需循环遍历敌人列表,看看这些条件是否满足。
在这种情况下,我建议你使用std::map来管理你创建的敌人对象。
假设你的Enemy类有一个检查删除条件的函数,例如:

bool Enemy::willbeDeleted() /* if true then will be deleted */
下面是一个使用std::map管理敌人对象的类:
EnemyManager.hpp
#include <map>
class EnemyManager {
public:
  /*
   * Get the Enemy Manager
   */
  static EnemyManager& Instance();
  /*!
   *  Delete the instance of EnemyManager
   */
  static void deleteInstance();
public:
  /* Create an enemy object */
  void createEnemy();
  /* Check all enemy objects and delete any fulfulling condition */
  void checkEnemy();
  virtual ~EnemyManager();
private:
  /* Make sure we can not call EnemyManager constructor directly */
  EnemyManager();
  EnemyManager(const EnemyManager& objManager);
  /* Instance of EnemyManager */
  static EnemyManager* enemyManager;
private:
  /* List of current enemy objects */
  std::map<int, A*> enemyList_;
  /* Identity of already-create object, it increases on creating a new object */
  int enemyIndex_;
};

EnemyManager.cpp

#include "EnemyManager.hpp"
#include <vector>
EnemyManager* EnemyManager::enemyManager = 0;
EnemyManager& EnemyManager::Instance()
{
  if (0 == enemyManager)
  {
    enemyManager = new EnemyManager();
  }
  return *enemyManager;
}
void EnemyManager::deleteInstance()
{
  if (0 != enemyManager) delete enemyManager;
}
EnemyManager::EnemyManager() : enemyList_(), enemyIndex_(0)
{}
EnemyManager::~EnemyManager() {
 /* Nothing todo */
}
void EnemyManager::createEnemy()
{
  enemyList_[enemyIndex_] = new Enemy();
  ++enemyIndex_;
}
void EnemyManager::checkEnemy()
{
  std::map<int, A*>::const_iterator itb = enemyList_.begin(),
                                ite = enemyList_.end(), it;
  // Vector containing id of enemy object to delete
  std::vector<int> enemyToDelete;
  for (it = itb; it != ite; ++it)
    if ((it->second)->willbeDeleted())
        enemyToDelete.push_back(it->first);
  // Delete enemies and remove them from map
  for (std::size_t idx = 0; idx < enemyToDelete.size(); ++idx)
  {
    delete enemyList_[enemyToDelete[idx]];
    enemyList_.erase(enemyToDelete[idx]);
  }
}

你可以这样使用这个类:在main.cpp

EnemyManager& enemyManager = EnemyManager::Instance();
if(rand() % 1000 > 998)
{
/* Create new enemy */
enemyManager.createEnemy();
}
/* Check all enemies */
enemyManager.checkEnemy();

有两个重要的函数:createEnemy控制创建新敌人对象的方式,checkEnemy验证对象并在需要时删除它们,并且enemyList_的大小永远不会增加:)
我相信用这种方法,删除敌人不会再减慢你的程序。
这种方法的缺点之一是创建对象的数量可能会受到2^(8*sizeof(enemyIndex_))

的限制。