这段代码有什么问题?似乎指针突然指向空值

时间:2015-10-07 09:19:10

标签: c++ pointers

这是我制作的简单游戏的一段代码。此例程检查阵列中的每个项目符号或敌人,如果它们已经超过屏幕,则将其从阵列中删除。 (此代码使用SDL2,但我认为不重要。)

void cleanEnemies(Enemy* a[], int* s)
{
    Enemy* e;
    for (int i = 0; i < *s; i++)
    {
        e = a[i];
        if (e->getX() < -75)
        {
            e->~Enemy();
            e = NULL;
            for (int j = i; j < *s; j++)
            {
                a[j] = a[j + 1];
            }
            (*s)--;
        }
    }
    printf("Enemy count: %i\n", *s);
}

void cleanMissiles(HomingMissile* a[], int* s)
{
    HomingMissile* m;
    for (int i = 0; i < *s; i++)
    {
        m = a[i];
        if (m->getX() < -75)
        {
            m->~HomingMissile();
            m = NULL;
            for (int j = i; j < *s; j++)
            {
                a[j] = a[j + 1];
            }
            (*s)--;
        }
    }
    printf("Missile count: %i\n", *s);
}

运行程序会生成指向无效内存位置的指针。谁能告诉我我做错了什么?感谢。

2 个答案:

答案 0 :(得分:1)

问题的原因是(我认为)内部for循环超出了数组的范围。

void cleanMissiles(HomingMissile* a[], int* s)
{
    HomingMissile* m;
    // Suggests there are *s entries, so last entry is (*s)-1
    for (int i = 0; i < *s; i++)
    {
        m = a[i];
        if (m->getX() < -75)
        {
            m->~HomingMissile();
            m = NULL;
            // Last value of j is (*s) - 1
            for (int j = i; j < *s; j++)
            {
                // Here it copies into a[(*s)] -1 from [a(*s)] which is invalid
                a[j] = a[j + 1];
            }
            (*s)--;
        }
    }
    printf("Missile count: %i\n", *s);
}

固定版本如下(依赖于如果在输入时不满足循环条件,for循环将永远不会执行的事实):

void cleanMissiles(HomingMissile* a[], int* s)
{
    HomingMissile* m;
    for (int i = 0; i < *s; i++)
    {
        m = a[i];
        if (m->getX() < -75)
        {
            m->~HomingMissile();
            m = NULL;
            for (int j = i + 1; j < *s; j++)
            {
                a[j - 1] = a[j];
            }
            (*s)--;
        }
    }
    printf("Missile count: %i\n", *s);
}

但不是解决这个问题,请让您的生活更轻松,切换到std::vector或更好std::list,并致电delete(假设您已分配new)而不是直接调用析构函数。

答案 1 :(得分:0)

使用std::vector<std::unique_ptr<T>>,它会变成像:

之类的东西
void cleanEnemies(std::vector<std::unique_ptr<Enemy>>& enemies)
{
    auto it = std::remove_if(enemies.begin(), enemies.end(),
                             [](const auto& enemy) {
                                  return enemy->getX() < -75;
                             });
    enemies.erase(it, enemies.end());
    std::cout << "Enemy count: " << enemies.size() << std::endl;
}

您甚至可以制作模板来处理EnemyHomingMissile

template <typename T>
void cleanObjects(std::vector<std::unique_ptr<T>>& objects, const std::string& objectName)
{
    auto it = std::remove_if(objects.begin(), objects.end(),
                             [](const auto& object) {
                                  return object->getX() < -75;
                             });
    objects.erase(it, objects.end());
    std::cout << objectName << " count: " << objects.size() << std::endl;
}

然后cleanEnemies / cleanMissiles可以改写为:

void cleanEnemies(std::vector<std::unique_ptr<Enemy>>& enemies)
{
    cleanObjects(enemies, "Enemy");
}

void cleanMissiles(std::vector<std::unique_ptr<HomingMissile>>& missiles)
{
    cleanObjects(missiles, "Missile");
}