Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
327 views
in Technique[技术] by (71.8m points)

c++ - Cannot figure out Seg Fault, lots of detail provided

I asked this question about a half hour ago, but the code had typos and I wasn't being very clear, so I've deleted and I'm trying again with a better format.

I'm getting a Segmentation Fault in my code, the problem seems to be at the function call if( (*trans).test((*this), *(*itr)) ) inside World::update():

void World::update(sf::Time dt)
{
    mPlayer->setVelocity(0.f, 0.f);

    while (!mCommandQueue.isEmpty()){
                Command cmd = mCommandQueue.pop();
                cmd.action(cmd.node, dt);
    }
    mSceneGraph.update(dt);
    adaptPlayerPosition();

    //Enemy Spawn engine
    if (mSpawnTimer.getElapsedTime().asSeconds() >= SPAWN_INTERVAL && mEnemies.size() < MAX_NUM_ENEMIES){
        float winX = mWindow.getDefaultView().getSize().x;
        float winY = mWindow.getDefaultView().getSize().y;
        float x = rand() % (int)winX;
        float y = rand() % (int)winY;
        spawnEnemy(x, y, EnemyType::Loner, IState::ILWander);
        mSpawnTimer.restart();
    }

    // FSM update
    IState::ID curEnemyStateID;
    FState curEnemyState;
    bool trigger = false;
    ICondition triggeredtrans;
    FState triggeredState;
    for(auto itr = mEnemies.begin(); itr != mEnemies.end(); ++itr){
        curEnemyStateID = (*itr)->getState();

        // set curState to whatever the enemy's curState is
        switch(curEnemyStateID){
        case 0:
            curEnemyState = LWander;
            break;
        default:
            break;
        }

        auto tState = curEnemyState.getTransitionStates().begin();
        for(auto trans = curEnemyState.getConditions().begin(); trans != curEnemyState.getConditions().end(); ++trans){
            if( (*trans).test((*this), *(*itr)) ){
                trigger = true;
                triggeredState = (*tState);
                break;
            }
            ++tState;
        }
        if(trigger){
            (*itr)->setState(IState::ILRushPlayer);
            curEnemyState = LRushPlayer;
        }
        curEnemyState.getAction()->doAction((*this), *(*itr));
    }
}

Context:

trans is an iterator for a std::vector<ICondition> conditions where each ICondition has a test(World& world, Enemy& enemy). itr is an iterator through a std::vector<Enemy*> that is held by World.

The conditions vector is filled in this function:

void World::initializeStates()
{
    Wander LWanderAction;
    LWander.setAction(LWanderAction);

    DistFromPlayer LWanderCond1(30);

    LWander.pushCondition(LWanderCond1);
    LWander.pushTransitionState(LRushPlayer);
}

LWander is a state (FState) in my Finite State Machine. Wander is a class that inherits IAction, and setAction accepts an IAction parameter: FState::setAction(IAction iact)

DistFromPlayer is a class that inherits ICondition.

FState::pushCondition(ICondition icond) and FState::pushTransitionState(Fstate state) should take their arguments and push them to Fstate's conditions and states vectors. (A transition's condition and matching target state should be at the same indices in both)

LWander and LRushPlayer are both members of World.


And that should cover everything. I don't know why I'm getting a SegFault, but I'm assuming that the problem is with how things are pushed into LWander in World::initializeStates(). I should also note that the SegFault occurs right after the first enemy is spawned in my game, which is also the same update frame that runs (*trans).test(*this, **itr) for the first time. All Enemys start in the LWander state.


ICondition's virtual bool test(World& world, Enemy& enemy); is defined as:

bool ICondition::test(World& world, Enemy& enemy){
    return false;
    //returns false by default, overwritten later
}

and DistFromPlayer's bool test(World& world, Enemy& enemy); is defined as:

bool DistFromPlayer::test(World& world, Enemy& enemy)
{
    std::cout << "DistFromPlayer (LWander's Transition) was reached
";
    return false;
}

and only contains a print statement for debugging purposes.


GDB's backtrace

#0  World::update (this=0x6464408, dt=...) at C:...World.cpp:97
#1  0x0040416b in GameState::update (this=0x64643f0, dt=...) at C:...GameState.cpp:22
#2  0x00402435 in StateStack::update (this=0x28fde0, dt=...) at C:...StateStack.cpp:19
#3  0x00403782 in Game::update (this=0x28fbc0, elapsedTime=...) at C:...Game.cpp:58
#4  0x004036a2 in Game::run (this=0x28fbc0) at C:...Game.cpp:48
#5  0x0040888b in main () at C:...main.cpp:7
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I am suspecting tState iterator. You only initialize it with begin() and increment it. I can't find any test against end() of the appropriate container. Or is it safe because of some relation between curEnemyState.getTransitionStates() and curEnemyState.getConditions() which I don't realize?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...