2

While working on a quick prototype on C++, I stumbled over this error. Now, I have read that the code means "access violation", but the origin or reason why is this happening completely eludes me. After narrowing down the cause, I noticed it's linked to me calling a particular function. However, the funny thing is that the code doesn't crash immediately after calling the function, but after the execution ends. In other words, the program starts, executes correctly (even the function that arises the error appears to work as intended), and then, after the main finishes, it crashes with that error code.

Whilst trying to debug my code, I went through the offending function line by line, commenting each instruction in order to see if anything that's done within makes the program crash. Surprisingly, the code crashes regardless of which instruction I comment out. Actually, I've come to comment out every single instruction within the function, leaving me with a stub that does nothing when called, and the program still fails upon finishing. However, if I comment out the call itself, the program stops issuing the error code. Therefore, the only reasonable solution to the problem has been not calling it at all, since even calling it and make it do nothing doesn't work.

I've literally got nothing on this. I don't know what's going on or why does my code behave like it does.

Just for reference, I'll include some snippets that may or may not be of particular importance.

a. The following is the offending function. Note that, in its current state, it does nothing, but the code still crashes when called. Please do also take into consideration this is a free function.

void createCollectable(entityx::EntityX& manager, TextureAtlas& atlas, unsigned int type)
{
    /*
    entityx::Entity collectable = manager.entities.create();

    collectable.assign<CollectableComponent>(type);
    collectable.assign<Scriptable>(std::bind(&collectableCallback, collectable));
    collectable.assign<Positionable>(sf::Vector2f(250.0f, 250.0f), sf::Vector2f(1.0f, 1.0f), sf::Vector2f(1.0f, 0.0f));
    collectable.assign<Movable>(0.0f, sf::Vector2f(0.0f, -220.0f));

    switch(type)
    {
    case CollectableIDs::EXTRA_BOMB:
        collectable.assign<Collidable>(createBoxCollisionShape(Game::collisionWorld, 10.0f, 10.0f, collectable));
        collectable.assign<Drawable>(atlas.getFrameAsSprite("EXTRA_BOMB"), 201, sf::BlendAlpha);
        break;

    case CollectableIDs::EXTRA_LIFE:
        collectable.assign<Collidable>(createBoxCollisionShape(Game::collisionWorld, 10.0f, 10.0f, collectable));
        collectable.assign<Drawable>(atlas.getFrameAsSprite("EXTRA_LIFE"), 201, sf::BlendAlpha);
        break;

    case CollectableIDs::POWER_LARGE:
        collectable.assign<Collidable>(createBoxCollisionShape(Game::collisionWorld, 10.0f, 10.0f, collectable));
        collectable.assign<Drawable>(atlas.getFrameAsSprite("POWER_LARGE"), 201, sf::BlendAlpha);
        break;

    case CollectableIDs::SUPER_POWER:
        collectable.assign<Collidable>(createBoxCollisionShape(Game::collisionWorld, 10.0f, 10.0f, collectable));
        collectable.assign<Drawable>(atlas.getFrameAsSprite("SUPER_POWER"), 201, sf::BlendAlpha);
        break;

    case CollectableIDs::POWER_MEDIUM:
        collectable.assign<Collidable>(createBoxCollisionShape(Game::collisionWorld, 7.5f, 7.5f, collectable));
        collectable.assign<Drawable>(atlas.getFrameAsSprite("POWER_MEDIUM"), 201, sf::BlendAlpha);
        break;

    case CollectableIDs::POWER_SMALL:
        collectable.assign<Collidable>(createBoxCollisionShape(Game::collisionWorld, 5.0f, 5.0f, collectable));
        collectable.assign<Drawable>(atlas.getFrameAsSprite("POWER_SMALL"), 201, sf::BlendAlpha);
        break;

    case CollectableIDs::MIASMA_LARGE:
        collectable.assign<Collidable>(createCircleCollisionShape(Game::collisionWorld, 5.0f, collectable));
        collectable.assign<Drawable>(atlas.getFrameAsSprite("POINT_LARGE"), 201, sf::BlendAlpha);
        break;

    case CollectableIDs::MIASMA_SMALL:
        collectable.assign<Collidable>(createCircleCollisionShape(Game::collisionWorld, 5.0f, collectable));
        collectable.assign<Drawable>(atlas.getFrameAsSprite("POINT_SMALL"), 201, sf::BlendAlpha);
        break;

    default:
        collectable.assign<Collidable>(createCircleCollisionShape(Game::collisionWorld, 5.0f, collectable));
        collectable.assign<Drawable>(atlas.getFrameAsSprite("POINT_SMALL"), 201, sf::BlendAlpha);
    }

    return collectable;
    */
 }

b. The following here is the code where the function is being called. Note that if I comment out the call to createCollectable here, the code ends successfully and doesn't crash at all.

void Game::run()
{
    loadResources();
    prepareActionMap(actionMap);
    ContactListener contactListener;
    collisionWorld.SetContactListener(&contactListener);
    collisionWorld.SetAllowSleeping(false);

    sf::Time timeSinceLastUpdate = sf::Time::Zero;

    /*These elements are for testing only, remove them after they're not used*/
    createPlayer(manager, actionMap, atlasHolder["player"]);
    createCollectable(manager, atlasHolder["bullets"], CollectableIDs::SUPER_POWER);
    createAdminEntity(manager);

    /*-----------------------------------------------------------------*/

    gameClock.restart();
    while(window.isOpen())
    {
        timeSinceLastUpdate += gameClock.restart();
        while(timeSinceLastUpdate > FPS)
        {
            timeSinceLastUpdate -= FPS;
            processEvents();
            update(FPS);
        }

        render(FPS);
    }
}

c. Just for the sake of completeness, here is how I'm declaring the free function in my .hpp file.

void createCollectable(entityx::EntityX& manager, TextureAtlas& atlas, unsigned int type);

d. The following free function, declared almost identically to the previous one, does work as expected and doesn't make the process return abnormally when called. Again, this one's for reference. Please do note that making the function return a value or not has had no bearing on whether calling the function throws or not (as you can see from the commented out return the first function had, which suggests it originally returned something, just like this function):

entityx::Entity createPlayer(entityx::EntityX& manager, thor::ActionMap<unsigned int>& actionMap, TextureAtlas& playerAtlas)
{
    entityx::Entity player = manager.entities.create();

    player.assign<Drawable>(playerAtlas.getFrameAsSprite("IDLE_1", true), 101, sf::BlendAlpha);
    player.assign<Positionable>(sf::Vector2f(100.0f, 100.0f), sf::Vector2f(1.0f, 1.0f), sf::Vector2f(1.0f, 0.0f));
    player.assign<Movable>(0.0f, sf::Vector2f(0.0f, 0.0f));
    player.assign<Controllable>();

    thor::ActionMap<unsigned int>::CallbackSystem& callbackSystem = (player.component<Controllable>())->callbackSystem;

    callbackSystem.connect(ActionIDs::LEFT_BUTTON_HELD, std::bind(&moveLeftCallback, player));
    callbackSystem.connect(ActionIDs::RIGHT_BUTTON_HELD, std::bind(&moveRightCallback, player));
    callbackSystem.connect(ActionIDs::UP_BUTTON_HELD, std::bind(&moveUpCallback, player));
    callbackSystem.connect(ActionIDs::DOWN_BUTTON_HELD, std::bind(&moveDownCallback, player));
    callbackSystem.connect(ActionIDs::HORIZONTAL_BUTTONS_UNPRESSED, std::bind(&stopHorizontalMovementCallback, player));
    callbackSystem.connect(ActionIDs::VERTICAL_BUTTONS_UNPRESSED, std::bind(&stopVerticalMovementCallback, player));
    callbackSystem.connect(ActionIDs::FOCUS_BUTTON_PRESSED, std::bind(&focusPlayerCallback, player));
    callbackSystem.connect(ActionIDs::FOCUS_BUTTON_UNPRESSED, std::bind(&unfocusPlayerCallback, player));

    thor::FrameAnimation playerIdleAnimation;
    playerIdleAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("IDLE_1"));
    playerIdleAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("IDLE_2"));
    playerIdleAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("IDLE_3"));
    playerIdleAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("IDLE_4"));

    thor::FrameAnimation playerMoveLeftAnimation;
    playerMoveLeftAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("LEFT_1"));
    playerMoveLeftAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("LEFT_2"));
    playerMoveLeftAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("LEFT_3"));
    playerMoveLeftAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("LEFT_4"));

    thor::FrameAnimation playerMoveRightAnimation;
    playerMoveRightAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("RIGHT_1"));
    playerMoveRightAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("RIGHT_2"));
    playerMoveRightAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("RIGHT_3"));
    playerMoveRightAnimation.addFrame(0.25f, playerAtlas.getFrameAsRect("RIGHT_4"));

    thor::Animator<DrawableAsset, unsigned int> playerAnimator;
    playerAnimator.addAnimation(AnimationIDs::PLAYER_IDLE, playerIdleAnimation, sf::seconds(0.3f));
    playerAnimator.addAnimation(AnimationIDs::PLAYER_MOVE_LEFT, playerMoveLeftAnimation, sf::seconds(0.3f));
    playerAnimator.addAnimation(AnimationIDs::PLAYER_MOVE_RIGHT, playerMoveRightAnimation, sf::seconds(0.3f));
    playerAnimator.playAnimation(AnimationIDs::PLAYER_IDLE, true);

    player.assign<Animatable>(playerAnimator);
    player.assign<Collidable>(createCircleCollisionShape(Game::collisionWorld, 2.5f, player), &onPlayerCollisionCallback);
    player.assign<Grazeable>(createCircleCollisionShape(Game::collisionWorld, 25.0f, player), &onPlayerGrazeCallback);
    player.assign<PlayerComponent>
    (
        3,
        3,
        5.0f,
        3.0f,
        150.0f,
        0,
        0,
        0.0f,
        false
    );

    return player;
}

Any help over this issue would be much appreciated. I don't believe giving out a list of used libraries would be of any interest since the problem seems not to be related to any of them, but just for completeness, the main libraries at work here are SFML, entityx and Box2D.

skink
  • 5,133
  • 6
  • 37
  • 58
Magnaillusion
  • 65
  • 2
  • 10
  • 4
    Try putting together a minimal example that reproduces the problem. This is a good idea for two reasons: 1) you will probably get more help from people here if you have a minimal example, and 2) often in the process of producing a minimal example you might find the problem you are seeking help for. – ilent2 Sep 09 '15 at 15:34
  • 2
    What is atlas holder, and where is it defined? If you are accessing invalid elements in some other object in the call, it is possible that that breaks your program. – zstewart Sep 09 '15 at 15:34
  • I suggest you deal with offenses by making the `switch` statement into a table. The code that accesses the table, the engine, would remain the same and all you need to do is modify the table (add, remove entries). This is called "data driven software". Yep, tables would simplify your program. – Thomas Matthews Sep 09 '15 at 15:35
  • Try calling `createCollectable(manager, atlasHolder["bullets"], unsigned int(0);` and `createCollectable(manager, atlasHolder["player"], unsigned int(0);` instead (for debugging purposes only). I suspect there is an issue with using `atlasHolder["bullets"]` – Class Skeleton Sep 09 '15 at 15:40
  • 1
    http://stackoverflow.com/help/mcve – xxbbcc Sep 09 '15 at 15:53
  • 1
    @rasteve Both calls result in an access violation. The `loadResources` method call at the start should take care of initializing both atlases. Just for reference, the atlas holder is of type `thor::ResourceHolder`, and its operator[] method looks like this: `thor::ResourceHolder< R, I, O >::operator[] (const I & id);` Where I is the type of element the resource holder is currently holding. – Magnaillusion Sep 09 '15 at 16:01
  • Well that rules that out. You'll have to narrow the code down to find the problem. I would start by looking at how createPlayer is using the playerAtlas argument perhaps... – Class Skeleton Sep 09 '15 at 16:15

1 Answers1

3

It appears that collisionWorld has longer lifetime duration than contactListener:

ContactListener contactListener;
collisionWorld.SetContactListener(&contactListener);

Are you sure that collisionWorld is not accessing contactListener after it goes out of scope? (e.g. in CollisionWorld dtor).

Try adding this at the end of the run() function:

collisionWorld.SetContactListener(0);
Ross Bencina
  • 3,822
  • 1
  • 19
  • 33
  • Yup, that seemed to be the problem. I changed the free functions to something more object oriented and made sure to unset the listener after I was done with the world. That seems to have alleviated the problem as the process is now returning 0. Many thanks for your answer. – Magnaillusion Sep 09 '15 at 17:57