(Проблема с рендерингом SDL) Возникло исключение C : нарушение доступа для чтения. ЭТО был nullptr

#c #pointers #exception #null #sdl

#c #указатели #исключение #null #sdl

Вопрос:

Всякий раз, когда я запускаю свою программу, я получаю исключение, генерируемое для двух отдельных строк кода, если я закомментирую одну из них, проблема переходит к другой, но обе ссылаются на одну и ту же переменную.

GameScreenManager.cpp:

 #pragma once
#include <SDL.h>
#include "Commons.h"
#include "GameScreenManager.h"
#include "GameScreenLevel1.h"
#include "GameScreen.h"

GameScreenManager::GameScreenManager(SDL_Renderer* renderer, SCREENS startScreen)
{
    SDL_Renderer* mRenderer;
    mRenderer = NULL;
    ChangeScreen(startScreen);
}

GameScreenManager::~GameScreenManager()
{
    mRenderer = NULL;
    delete mCurrentScreen;
    mCurrentScreen = NULL;
}

void GameScreenManager::Render()
{
    mCurrentScreen->Render();
}

void GameScreenManager::update(float deltaTime, SDL_Event e)
{
    mCurrentScreen->Update(deltaTime, e);
}

void GameScreenManager::ChangeScreen(SCREENS newScreen)
{
    //Clear up the old screen
    if (mCurrentScreen != NULL)
    {
        delete mCurrentScreen;
    }

    GameScreenLevel1* tempScreen;


    switch (newScreen)
    {
    case SCREEN_INTRO:
        break;
    case SCREEN_MENU:
        break;
    case SCREEN_LEVEL1:
        tempScreen = new GameScreenLevel1(mRenderer);
        mCurrentScreen = (GameScreen*)tempScreen;
        tempScreen = NULL;
        break;
    case SCREEN_LEVEL2:
        break;
    case SCREEN_GAMEOVER:
        break;
    case SCREEN_HIGHSCORES:
        break;
    default:
            break;
    }
}
 

GameScreenManager.h:

 #pragma once
#ifndef _GAMESCREENMANAGER_H
#define _GAMESCREENMANAGER_H
#include <SDL.h>
#include "Commons.h"

class GameScreen;

class GameScreenManager
{
    private:
        SDL_Renderer*    mRenderer;
        GameScreen*      mCurrentScreen;

    public:
        GameScreenManager(SDL_Renderer* renderer, SCREENS startScreen);
        ~GameScreenManager();

        void Render();
        void update(float deltaTime, SDL_Event e);
        void ChangeScreen(SCREENS newScreen);
};

#endif //_GAMESCREENMANAGER_H
 

В настоящее время проблема возникает в строке 24;

     mCurrentScreen->Render();
 

Однако, если я закомментирую эту строку, она появится в строке 29:

     mCurrentScreen->Update(deltaTime, e);
 

«Возникло необработанное исключение: нарушение доступа для чтения.
это был nullptr. произошло »

Комментарии:

1. Программа часто вылетает за много миль от того места, где на самом деле была ошибка. Сообщение об ошибке this было nullptr предполагает, что вы должны выяснить, почему this это было nullptr . Было mCurrentScreen = (GameScreen*)tempScreen; пропущено?

Ответ №1:

По-видимому, поле mCurrentScreen имеет значение NULL при вызове Render() или update() . Либо защитите вызовы, проверив mCurrentScreen на NULL:

 void GameScreenManager::Render()
{
    if (mCurrentScreen != NULL)
        mCurrentScreen->Render();
}

void GameScreenManager::update(float deltaTime, SDL_Event e)
{
    if (mCurrentScreen != NULL)
        mCurrentScreen->Update(deltaTime, e);
}
 

или убедитесь, что установлен mCurrentScreen перед вызовом Render() или Update() .

Комментарии:

1. Я добавил операторы if, чтобы проверить, является ли mCurrentScreen != NULL, и действуйте соответственно, однако я все равно получаю исключение, однако на этот раз для операторов if.

2. установите для mCurrentScreen значение NULL после удаления его в ChangeScreen()

3.Если mCurrentScreen не гарантируется, что перед его использованием будет указано на что-то безопасное, вы обречены окружать каждое использование с if (mCurrentScreen != NULL) помощью . Это воспроизводит ошибку, потому что вы будете постоянно находить случаи, когда она не была установлена. и не проверялось. Вам гораздо лучше убедиться, что это mCurrentScreen всегда указывает на что-то безопасное.

4. Я установил mCurrentScreen равным NULL после удаления mCurrentScreen и все равно получаю исключение. Я даже полностью удалил этот оператор if и все равно не повезло.

5. Если исключение генерируется в операторе if, вероятно, что-то не так с вашей сборкой — попробуйте очистить / перестроить, удалить все промежуточные файлы и т.д. Вы также должны инициализировать mCurrentScreen равным NULL в конструкторе, но это не поможет вам создавать исключения для «if».

Ответ №2:

Как оказалось, я фактически пропустил строку кода, которая устанавливала mCurrentScreen, и оператор switch проходил неправильно, поэтому он не срабатывал. Кроме того, переменная mRenderer не была настроена правильно ни в одном из моих файлов cpp, поэтому она возвращала «Недопустимый рендеринг» всякий раз, когда я пытался его использовать. Ниже приведен рабочий код, спасибо всем за помощь, он направил меня в правильном направлении;

 #pragma once
#include <SDL.h>
#include "Commons.h"
#include "GameScreenManager.h"
#include "GameScreenLevel1.h"
#include "GameScreen.h"

GameScreenManager::GameScreenManager(SDL_Renderer* renderer, SCREENS startScreen)
{
    mRenderer = renderer;
    GameScreen* mCurrentScreen = NULL;
    ChangeScreen(startScreen);
}

GameScreenManager::~GameScreenManager()
{
    mRenderer = NULL;
    delete mCurrentScreen;
    mCurrentScreen = NULL;
}

void GameScreenManager::Render()
{
    mCurrentScreen->Render();
}

void GameScreenManager::Update(float deltaTime, SDL_Event e)
{
    mCurrentScreen->Update(deltaTime, e);
}

void GameScreenManager::ChangeScreen(SCREENS newScreen)
{
    //Clear up the old screen
    if (mCurrentScreen != NULL)
    {
        delete mCurrentScreen;
    }

    GameScreenLevel1* tempScreen;

    switch (newScreen)
    {
    case SCREEN_INTRO:
        break;
    case SCREEN_MENU:
        break;
    case SCREEN_LEVEL1:
        tempScreen = new GameScreenLevel1(mRenderer);
        mCurrentScreen = (GameScreen*)tempScreen;
        tempScreen = NULL;
        break;
    case SCREEN_LEVEL2:
        break;
    case SCREEN_GAMEOVER:
        break;
    case SCREEN_HIGHSCORES:
        break;
    default:
        break;
    }
}