【问题标题】:C++ Segmentation fault when erasing from vector [duplicate]从向量中擦除时出现C++分段错误[重复]
【发布时间】:2017-05-22 03:05:19
【问题描述】:

不是 iterate vector, remove certain items as I go 的重复项,因为我已经尝试过该问题中使用的解决方案!

所以我正在制作一个游戏引擎,其中有一个名为“Scene”的类,它有一个游戏对象向量。

场景有一个名为“destantiate”的函数,用于“删除”游戏对象。

当我调用此函数时,尝试使用 std::vector::erase 函数时出现分段错误。

我认为这可能与另一个循环迭代向量有关,它试图访问向量中已被擦除的指针?

看看下面的代码:

#include "Scene.h"
#include "Instance.h"


Scene::Scene() {
    this->camera = new Camera(0, 0);
}

void Scene::instantiate(Instance *instance) {
    this->instances->push_back(instance);
}

void Scene::destantiate(Instance &instance) {
    instance.trash = true;
}

void Scene::tick(float delta) {
    this->camera->tick(delta);
    for(std::vector<Instance*>::iterator it = this->instances->begin(); it != this->instances->end(); ++it) {
        if ((*it)->trash) {
            std::vector<Instance*>::iterator position = std::find(
            this->instances->begin(),
            this->instances->end(),
            (*it)
            );

            if (position != this->instances->end()) {
                this->instances->erase(position);
            }

            continue;
        }
        (*it)->collisionBox->width = (*it)->sprite->getCurrentImage()->getWidth();
        (*it)->collisionBox->height = (*it)->sprite->getCurrentImage()->getHeight();
        (*it)->tick(delta);
    }
}

void Scene::draw(float delta) {
    this->camera->draw(delta);
    for(std::vector<Instance*>::iterator it = this->instances->begin(); it != this->instances->end(); ++it) {
        if ((*it)->trash) { continue; }
        glPushMatrix();

        if ((*it)->centeredOrigo) {
            glTranslatef((*it)->x - (*it)->sprite->getCurrentImage()->getWidth()/2, (*it)->y - (*it)->sprite->getCurrentImage()->getHeight()/2, 0.0f);
        } else {
            glTranslatef((*it)->x, (*it)->y, 0.0f); 
        }

        if ((*it)->centeredOrigo) {
            glTranslatef(((*it)->sprite->getCurrentImage()->getWidth()/2), ((*it)->sprite->getCurrentImage()->getHeight()/2), 0);
        }

        glRotatef((*it)->rotation, 0.0f, 0.0f, 1.0f);

        if ((*it)->centeredOrigo) {
            glTranslatef(-((*it)->sprite->getCurrentImage()->getWidth()/2), -((*it)->sprite->getCurrentImage()->getHeight()/2), 0);
        }

        (*it)->draw(delta);

        glPopMatrix();
    }
}

std::vector::erase 函数在“tick”函数中被调用,它检查对象是否具有“trash”标志。

这是运行时在游戏对象类内部调用“destantiate”函数的地方:

#include "SDLOpenGL.h"
#include "TestObj.h"


TestObj::TestObj(float x, float y) : Instance(x, y) {
    this->sprite->addImage(game.loader->load("assets/card.png"));
    this->centeredOrigo = true;
}

void TestObj::tick(float delta) {
    if (this->trash) { return; }
    //this->x = game.getMousePosition().x;
    //this->y = game.getMousePosition().y;
    this->rotation += 2.0f;

    if (game.keyboardDown(SDL_SCANCODE_LEFT)) {
        this->x -= 9.5f;
    }
    if (game.keyboardDown(SDL_SCANCODE_RIGHT)) {
        this->x += 9.5f;
    }
    if (game.keyboardDown(SDL_SCANCODE_UP)) {
        this->y -= 9.5f;
    }
    if (game.keyboardDown(SDL_SCANCODE_DOWN)) {
        this->y += 9.5f;

        //Segmentation fault
        game.getCurrentScene()->destantiate(*this);
    }
}

void TestObj::draw(float delta) {
    if (this->trash) { return; }

    this->sprite->draw(delta);
    this->collisionBox->draw(delta);
}

输出:

Segmentation fault: 11

valgrind 说了一些关于“使用未初始化的指针”的事情

【问题讨论】:

  • 是的,您不能在迭代向量时对其进行变异。但是你不应该有这样的垃圾场。您可能需要第二个向量来存储应该删除的对象。另一种选择是对向量的副本进行操作,但我不建议这样做。
  • 你试过this吗?
  • @User9182736455 嗯,存储应该删除的对象听起来很有趣。但是假设我正在迭代它(“删除向量”)并从主向量中删除东西。迭代主向量的迭代器不会中断并导致分段错误吗?
  • 所以基本上,您正在创建另一个指向同一元素的迭代器,使用std::find,擦除该其他迭代器,希望初始迭代器 将保持有效吗?不,这样不行。
  • @A.S.H 那么我该如何以一种有效的方式正确地做到这一点呢?

标签: c++ c++11 pointers segmentation-fault stdvector


【解决方案1】:

我想你误解了我的意思。我会尝试用代码来解释:

void deinstantiate(GameObject go) {
    flaggedForDeletion.push_back(go);
}

void tick(float delta) {
    for(auto it = gameObjects.begin(); it != gameObjects.end(); ++it) {
        it->tick(delta);
    }

    for(auto it = flaggedForDeletion.begin(); it != flaggedForDeletion.end(); ++it) {
        std::remove(vec.begin(), vec.end(), *it);
    }
}

因此,您只需存储要删除的对象,然后再将其删除。你不能在迭代它们时删除它们,因为它会使你的迭代器失效。

除了this 解决方案对您有效。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2018-08-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-17
  • 1970-01-01
  • 2020-09-08
  • 1970-01-01
  • 2015-09-03
相关资源
最近更新 更多