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;
}
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.
#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
#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
#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