Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular dependency: can't delete an incomplete type

I don't understand why I get this compiler errors:

error C2027: use of undefined type 'GameState'
note: see declaration of 'GameState'
error C2338: can't delete an incomplete type warning C4150: deletion of pointer to incomplete type 'GameState'; no destructor called

This is the relevant code:

#pragma once
#include <SFML\Graphics.hpp>
#include "SpawnManager.h"
#include "Resource.h"
#include <stack>
#include <memory>
class GameState;

class Controller
{
public:
    Controller();
    void run();
    void setPlayerScore(unsigned score);
    sf::RenderWindow& getWindow() { return m_window; }
    void addState(const States& state);
    void changeState(const States& state);
    GameState* getState() const;
    void popState();
    void add_state(const States& type, Controller * cont);
    ~Controller() {}

private:
    SpawnManager<States, GameState> m_sFactory;
    sf::RenderWindow m_window;
    ScoreRecord m_playerScore;
    std::stack<std::unique_ptr<GameState>> m_screens;
};

#pragma once
#include <SFML\Graphics.hpp>
#include <memory>
#include "Controller.h"

//State design pattern
class GameState
{
public:
    explicit GameState(Controller* state_holder);
    GameState(const GameState&) = delete;
    GameState(GameState&&) = delete;
    GameState& operator=(const GameState&) = delete;
    GameState& operator=(GameState&&) = delete;
    virtual ~GameState() = default;

    virtual void displayState() = 0;
    virtual void updateStage() = 0;
    virtual void handleEvent(sf::Event& event) = 0;

protected:
    std::unique_ptr<Controller> m_state;
};

Any ideas how to fix this?

like image 405
Talor T Avatar asked Jun 19 '17 14:06

Talor T


1 Answers

The definition of the destructor of std::unique_ptr<T> requires T to be complete i.e. defined, not just declared. Since a std::unique_ptr<GameState> is a(n indirect) member of Controller, the definition of destructor ~Controller requires the definition of the destructor of std::unique_ptr<GameState> and therefore also the definition of GameState, which was not provided.

Solution: Define GameState before you define ~Controller. A minimal example:

struct GameState;

// 1. Definition of Controller
struct Controller
{
    ~Controller();
    std::stack<std::unique_ptr<GameState>> m_screens;
};

// 2. Definition of GameState
struct GameState
{
    std::unique_ptr<Controller> m_state;
};

// 3. Definition of Controller::~Controller
Controller::~Controller(){} // or = default;

P.S. Consider that you can never have a GameState be pointed by a Controller that points to that same GameState. In such situation you would end up with an infinite recursion of destructions of already destructed objects. And multiple GameStates can not own the same Controller and vice versa. Consider whether your ownership structure makes sense. I suspect that you need either shared ownership, or non-owning referral.

like image 116
eerorika Avatar answered Sep 23 '22 01:09

eerorika