c++ - “这”为0xDDDDDDDD:弹出堆栈时发生读取访问冲突

标签 c++ memory-management stack sfml game-development

我目前正在尝试使用SFML构建游戏引擎的框架,并且正在学习如何利用Gamestate堆栈结构来将代码划分为可读部分。
我创建了一个基本的TestGameState类,该类扩展了一个抽象类GameState,其他Gamestate类将在其上构建。在我的Game类中,我仅创建一个窗口,运行一个基本的游戏循环,并调用Gamestate更新方法。每个类的代码是:
GameState.h

#pragma once
#include "Game.h"

class GameState {
public: 
    Game* game = NULL;
    virtual void update() = 0;
    virtual void draw() = 0;
    virtual void handleInput() = 0;
};
TestState.cpp ,它是GameState类的扩展
#include "TestState.h"
#include "testGameplayState.h"
using namespace sf;

TestState::TestState(Game* g){
    game = g;
    texture.loadFromFile("graphics/grass.png");
    sprite.setTexture(texture);
    sprite.setPosition(Vector2f(0, 0));
}

void TestState::handleInput(){
    Event event;

    while (game->window.pollEvent(event)) {
        if (event.type == Event::KeyPressed) {
            if (event.key.code == Keyboard::O) {
                game->pushState(new TestState(game));
            }
            else if (event.key.code == Keyboard::P) {
                game->popState();
            }
        }
    }
}

void TestState::update(){}

void TestState::draw(){
    game->window.draw(sprite);
}
最后是游戏对象,它处理状态:
Game.cpp
#include "Game.h"
#include "GameState.h"
using namespace sf;

//Please note that states is a private stack variable.

Game::Game(){
    window.create(VideoMode(1920, 1080), "GameState Test", Style::Fullscreen);
}


Game::~Game() {
    while (!states.empty()) {
        popState();
    }
}

void Game::run() {
    while (window.isOpen()) {
        if (currentState() == nullptr) {
            std::cout << "Nullptr" << std::endl;
            window.close();
        }

        //Handle input
        currentState()->handleInput();

        //Update
        currentState()->update();

        //Draw
        window.clear();

        currentState()->draw();

        window.display();
    }
}

GameState* Game::currentState() {
    if (this->states.empty()) {
        return nullptr;
    }
    else {
        return this->states.top();
    }
}

void Game::pushState(GameState* state) {
    this->states.push(state);
}

void Game::popState() {
    delete this->states.top();
    this->states.pop();
}
每当我尝试创建新的游戏状态对象时,都可以将它们添加到堆栈中,并可以毫无问题地使用它们。但是,当我尝试弹出当前游戏状态时,它立即退出并在 TestState.cpp 中的while (game->window.pollEvent(event))行上抛出错误,说:Exception thrown: read access violation. **this** was 0xDDDDDDDD.错误中的“this”大概是每个状态都持有的游戏对象指针,因为在调试器中它表明游戏对象的值为0xDDDDDDDD。我知道0xDDDDDDDD表示在该地址读取的内存已被删除,但是,我不知道为什么会这样。我希望只有游戏状态会被删除,但是由于某种原因,似乎游戏指针也被删除了。
我使用thisthis作为如何构造游戏状态类的指南。
我如何能够解决此问题?非常感谢您的帮助。

最佳答案

使用@ OS2和@Some程序员的提示,我能够解决此问题。添加检查以确保我永远不会对空指针进行操作后,我在主游戏循环中更改了方法调用的顺序。这是新循环的样子:
Game.cpp

void Game::run()
{
    while (window.isOpen())
    {
        //Handle input
        currentState()->handleInput();

        //Check if there are more states
        if (currentState() == nullptr)
        {
            std::cout << "Nullptr, exiting program" << std::endl;
            window.close();

            break;
        }

        //Update
        currentState()->update();

        //Draw
        window.clear();

        currentState()->draw();

        window.display();
    }
}
发生的事情是我弹出了堆栈,该堆栈工作正常,但随后立即继续对空指针进行操作。通过检查输入处理后是否存在空指针,可以避免此问题。
更重要的是-修复0xDDDDDDDD错误-只需一行即可修复内存错误。
如果您通过用户输入来弹出状态,就像我在上面提到的那样,请确保一旦弹出状态就跳出循环。否则,while()循环将在状态终止后继续执行,并且由于状态不再存在而将引发错误。我编辑的输入处理代码如下所示:
TestState.cpp
void TestState::handleInput()
{
    std::cout << "Handling input" << std::endl;

    Event event;

    while (game->window.pollEvent(event))
    {
        if (event.type == Event::KeyPressed)
        {
            if (event.key.code == Keyboard::O)
            {
                game->pushState(new TestState(game));
            }
            else if (event.key.code == Keyboard::P)
            {
                game->popState();
                
                break;
            }
        }
    }
}
希望对其他有此问题的人有所帮助。感谢@ OS2和@Some编程人员为您发现问题提供的帮助。

关于c++ - “这”为0xDDDDDDDD:弹出堆栈时发生读取访问冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63092188/

相关文章:

C++ 变量内存分配

memory-management - 如何计算Bert的内存需求?

go - 结构中的线程,函数参数对于新的 goroutine 来说太大

c - 指针间接与在堆栈上分配的成本是多少?

c++ - 将数据提供给 ChartView (LineSeries) - QML

c++ - 与 __stdcall 函数指针声明等价的 clang 是什么?

c - 这个 C 程序中的内存分配是如何完成的?

当 hasNextInt() 遇到输入结束时,Java 突然终止

c++ - 如何只声明一个对象而不在标题中定义

c++ - C++17 会允许嵌套类的前向声明吗?