(C ++) Как удалить базовый класс после удаления дочернего класса при наследовании? - PullRequest
0 голосов
/ 16 февраля 2019

Я делаю игру с C ++ и SDL.Существует класс Screen .и есть классы StartScreen и MultiplaySettingScreen , которые наследуют класс Screen .

Я обнаружил на консоли, чтоКогда я покидаю всю игру, эти классы создаются по порядку, но для деконструкции, объект ' Screen ' не удаляется (освобождается), тогда как ' StartScreen ' и ' MultiplaySettingScreen 'объекты удалены (освобождены).Я думаю, что это утечка памяти.

Конструктор экрана ()!

Конструктор StartScreen ()!

Конструктор MultiplaySettingScreen ()!

...

Конструктор StartScreen ()!

Конструктор MultiplaySettingScreen ()!

Что происходит?Что я сделал не так?


вот код.

' Экран '

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

Ответы [ 2 ]

0 голосов
/ 16 февраля 2019

Эта программа

#include "StartScreen.h"
#include "MultiplaySettingScreen.h"

int main() {
    { StartScreen ss(nullptr); }
    { MultiplaySettingScreen mss; }
}

выводит

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

Я полагаю, вам не хватило вывода трассировки из вашего 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
0 голосов
/ 16 февраля 2019

" Я обнаружил на консоли, что когда я покидаю всю игру, эти классы строятся по порядку, но для деконструкции, объект« Экран »не удаляется (освобождается), тогда как« StartScreen »иОбъекты 'MultiplaySettingScreen' удалены (освобождены). Я думаю, что это утечка памяти."

Пустой ( по умолчанию ) деструктор всегда уничтожаеткласс, когда выходит за рамки или вызывается явно ... Поэтому, как отмечалось ранее, у нас нет информации относительно как вы можете знатьчто Screen не было уничтожено ...

Также этот член:

SDL_Renderer *rend = nullptr;

SDL_Renderer является structчасть C-библиотеки SDL и, следовательно, не обладает C ++ class - деструктором ... Следовательно, ваш рендереростается повисшим при уничтожении Screen класса ...

virtual ~Screen(){
    // Explicitly destroy the renderer...
    SDL_DestroyRenderer(rend);
    screen->~GameObject(); // Destroy the screen gameobject...
    arrow->~GameObject(); // Destroy the arrow gameobject...
};
...