Search code examples
c++sdl

(C++) How to delete base class after deleting child class when inherited?


I'm making a game with C++ and SDL. There is 'Screen' class. and there are 'StartScreen' and 'MultiplaySettingScreen' classes, which inherit 'Screen' class.

I found out on the console that when I quit the whole game, These classes are constructed in order but for deconstructing, 'Screen' object is not deleted(freed), whereas 'StartScreen' and 'MultiplaySettingScreen' objects are deleted(freed). I think it's a memory leak.

Screen constructor()!

StartScreen constructor()!

MultiplaySettingScreen constructor()!

...

StartScreen constructor()!

MultiplaySettingScreen constructor()!

What's going on? What did I do wrong?


here's the code.

'Screen'

class Screen
{
protected:
    SDL_Renderer *rend = nullptr;
    GameObject *screen = nullptr;
    GameObject *arrow = nullptr;
public:
    Screen();
    Screen(SDL_Renderer *renderer);
    virtual ~Screen(){};
    virtual void handleEvents(const Uint8 *keystate, bool *isSelecting, bool *isSingle, bool *isMulti){};
    virtual void Update(){};
    virtual void Render(){};
};

Screen::Screen()
{}

Screen::Screen(SDL_Renderer *renderer)
{
    std::cout << "Screen constructor()!" << std::endl;

    rend = renderer;
    screen = new GameObject("images/startscreen.png", GAME_WIDTH, GAME_HEIGHT, 0, 0, "img");
    arrow = new GameObject("images/arrow.png", 30, 30, 250, 330, "img");
}

'StartScreen'

class StartScreen: public Screen
{
public:
    StartScreen(SDL_Renderer *renderer);
    ~StartScreen();
    virtual void handleEvents(const Uint8 *keystate, bool *isSelecting, bool *isSingle, bool *isMulti);
    virtual void Update();
    virtual void Render();
};

   StartScreen::StartScreen(SDL_Renderer *renderer): Screen(renderer)
    {
        std::cout << "StartScreen constructor()!" << std::endl;

        singlePlayMode = new GameObject("SINGLE PLAY", MODE_WIDTH, MODE_HEIGHT, 300, 320);
        multiPlayMode = new GameObject("MULTI PLAY", MODE_WIDTH, MODE_HEIGHT, 300, 380);
        title = new GameObject("Pikachu Volleyball", 400, MODE_HEIGHT, 200, 50);
        explaination = new GameObject("Press Enter on any mode..", 400, MODE_HEIGHT, 200, 200);
        copyright = new GameObject("(C) Jinko, All rights reserved", 400, 50, 200, 500);
    }

StartScreen::~StartScreen()
{
    std::cout << "StartScreen deconstructor()!" << std::endl;

    delete singlePlayMode;
    delete multiPlayMode;
    delete title;
    delete explaination;
    delete copyright;
    delete arrow;
    delete screen;
}

'MultiplaySettingScreen'

class MultiplaySettingScreen: public Screen
{
private:
    std::string connectingIp = "127.0.0.1";
    std::string connectingPort = "80";
public:
    MultiplaySettingScreen();
    ~MultiplaySettingScreen();
    virtual void handleEvents(const Uint8 *keystate, bool *isSelecting, bool *isSingle, bool *isMulti);
    virtual void Update();
    virtual void Render();
};

MultiplaySettingScreen::MultiplaySettingScreen()
{
    std::cout << "MultiplaySettingScreen constructor()!" << std::endl;

    host = new GameObject("Host", 400, 400, 200, 200);
    guest = new GameObject("Guest", 400, 400, 300, 200);
    ipInput = new GameObject("Connecting IP: ", 400, 200, 200, 200);
    portInput = new GameObject("Connecting PORT: ", 400, 50, 200, 500);
    SDL_StartTextInput();

    if (SDLNet_Init() == -1)
        std::cout << "SDLNET init failed" << std::endl;
    IPaddress ip;

}

MultiplaySettingScreen::~MultiplaySettingScreen()
{
    std::cout << "MultiplaySettingScreen deconstructor()!" << std::endl;

    SDLNet_Quit();

    delete host;
    delete guest;
    delete ipInput;
    delete portInput;
}


Solution

  • This program

    #include "StartScreen.h"
    #include "MultiplaySettingScreen.h"
    
    int main() {
        { StartScreen ss(nullptr); }
        { MultiplaySettingScreen mss; }
    }
    

    outputs

    (rendered) Screen constructor()!
    StartScreen constructor()!
    StartScreen deconstructor()!
    Screen destructor()!
    (default) Screen constructor()!
    MultiplaySettingScreen constructor()!
    MultiplaySettingScreen deconstructor()!
    Screen destructor()!
    

    I believe you lacked trace output from your Screen class to show you the whole story.

    Screen.h

    #ifndef SCREEN_H_INCLUDED
    #define SCREEN_H_INCLUDED
    
    #include <memory>
    #include <iostream>
    
    #include "stuff.h" // or whatever the SDL header(s) are called
    
    class Screen
    {
    protected:
        SDL_Renderer *rend = nullptr;
        std::unique_ptr<GameObject> screen;
        std::unique_ptr<GameObject> arrow;
    public:
        Screen();
        explicit Screen(SDL_Renderer *renderer);
        virtual ~Screen();
        Screen(Screen const&) = delete;
        Screen& operator=(Screen const&) = delete;
    
        virtual void handleEvents(const Uint8 *keystate, bool *isSelecting, bool *isSingle, bool *isMulti){}
        virtual void Update(){}
        virtual void Render(){}
    };
    
    Screen::Screen(SDL_Renderer *renderer)
    : rend(renderer)
    , screen(std::make_unique<GameObject>("images/startscreen.png", GAME_WIDTH, GAME_HEIGHT, 0, 0, "img"))
    , arrow(std::make_unique<GameObject>("images/arrow.png", 30, 30, 250, 330, "img"))
    {
        std::cout << "(rendered) Screen constructor()!\n";
    }
    
    Screen::Screen() {
        std::cout << "(default) Screen constructor()!\n";
    }
    
    Screen::~Screen() {
        std::cout << "Screen destructor()!\n";
    }
    
    #endif  // SCREEN_H_INCLUDED
    

    StartScreen.h

    #ifndef STARTSCREEN_H
    #define STARTSCREEN_H
    
    #include "Screen.h"
    
    class StartScreen : public Screen {
    public:
        explicit StartScreen(SDL_Renderer *renderer);
        ~StartScreen() override;
    
        void handleEvents(const Uint8 *keystate, bool *isSelecting, bool *isSingle, bool *isMulti) override {}
        void Update() override {}
        void Render() override {}
    
    private:
        std::unique_ptr<GameObject> singlePlayMode;
        std::unique_ptr<GameObject> multiPlayMode;
        std::unique_ptr<GameObject> title;
        std::unique_ptr<GameObject> explaination;
        std::unique_ptr<GameObject> copyright;
    };
    
    StartScreen::StartScreen(SDL_Renderer *renderer)
            : Screen(renderer),
              singlePlayMode(std::make_unique<GameObject>("SINGLE PLAY", MODE_WIDTH, MODE_HEIGHT, 300, 320)),
              multiPlayMode(std::make_unique<GameObject>("MULTI PLAY", MODE_WIDTH, MODE_HEIGHT, 300, 380)),
              title(std::make_unique<GameObject>("Pikachu Volleyball", 400, MODE_HEIGHT, 200, 50)),
              explaination(std::make_unique<GameObject>("Press Enter on any mode..", 400, MODE_HEIGHT, 200, 200)),
              copyright(std::make_unique<GameObject>("(C) Jinko, All rights reserved", 400, 50, 200, 500)) {
        std::cout << "StartScreen constructor()!\n";
    }
    
    StartScreen::~StartScreen() {
        std::cout << "StartScreen deconstructor()!\n";
    }
    
    #endif  // STARTSCREEN_H
    

    MultiplaySettingScreen.h

    #ifndef MULTIPLAYSETTINGSCREEN_H
    #define MULTIPLAYSETTINGSCREEN_H
    
    #include "Screen.h"
    
    class MultiplaySettingScreen : public Screen {
    private:
        std::string connectingIp = "127.0.0.1";
        std::string connectingPort = "80";
    public:
        MultiplaySettingScreen();
        ~MultiplaySettingScreen() override;
    
        void handleEvents(const Uint8 *keystate, bool *isSelecting, bool *isSingle, bool *isMulti) override {}
        void Update() override {}
        void Render() override {}
    
        std::unique_ptr<GameObject> host;
        std::unique_ptr<GameObject> guest;
        std::unique_ptr<GameObject> ipInput;
        std::unique_ptr<GameObject> portInput;
    };
    
    MultiplaySettingScreen::MultiplaySettingScreen()
            : Screen(), host(std::make_unique<GameObject>("Host", 400, 400, 200, 200)),
              guest(std::make_unique<GameObject>("Guest", 400, 400, 300, 200)),
              ipInput(std::make_unique<GameObject>("Connecting IP: ", 400, 200, 200, 200)),
              portInput(std::make_unique<GameObject>("Connecting PORT: ", 400, 50, 200, 500)) {
        std::cout << "MultiplaySettingScreen constructor()!\n";
    
        SDL_StartTextInput();
    
        if (SDLNet_Init() == -1)
            std::cout << "SDLNET init failed\n";
        IPaddress ip;
    }
    
    MultiplaySettingScreen::~MultiplaySettingScreen() {
        std::cout << "MultiplaySettingScreen deconstructor()!\n";
        SDLNet_Quit();
    }
    
    #endif  // MULTIPLAYSETTINGSCREEN_H