首页 文章

堆栈分配的类--C发生不需要的析构函数调用

提问于
浏览
1

在Game类函数中,我将一个Boundary类分配给堆栈

void Game::loadContent()
{
    Boundary b(this, body); 
}

边界类有一个指向主Game类的指针和一个指向刚体的指针 . 我不确定我是否应该使用每个参考?这里的一些清晰度将有助于后面解释的原因 .

class Boundary : public DynamicEntity
{
public:
    Boundary(Game *game, btRigidBody *body);
    ~Boundary(void);

    // Override functions
    virtual void draw(float dt);
    virtual glm::vec3 getPosition();
    virtual void update(float dt);
};

DynamicEntity类指定正文并在其析构函数中处理指针删除 .

class DynamicEntity : public Entity
{
public:
    virtual ~DynamicEntity(void);

    virtual void draw(float dt) = 0;
    btRigidBody* getBody();
    glm::vec3 getPosition() = 0;
    virtual void update(float dt) = 0;

protected:
    explicit DynamicEntity(Game *game, btRigidBody *body);
    btRigidBody *m_body;
};

DynamicEntity.cpp析构函数

DynamicEntity::~DynamicEntity(void)
{
    m_game->m_dynamicsWorld->removeRigidBody(m_body);

    delete m_body;
}

DynamicEntity派生自所有称为Entity的游戏对象的基类

Entity.h

class Entity
{
public:
    // Make destructor virtual as this is a base class
    virtual ~Entity(void);

    virtual void draw(float dt) = 0;
    int getID();                                
    virtual glm::vec3 getPosition() = 0;
    virtual void update(float dt) = 0;          

protected:
    explicit Entity(Game *game);                // Abstract base constructor

    Game *m_game;
    int m_id;                                   // Unique ID
};

我不能在这个类的析构函数中调用Game类指针上的delete,但这就是为什么我不确定作为指针传递是否是正确的方法(而不是引用)?

Entity::~Entity(void)
{
    // Derived class destructors are called first
    delete m_game;  // ERROR
}

Entity类添加一个指向自身的指针,可以通过Game类中的列表进行访问(对于在主Game类中迭代和调用实体函数很有用) .

Entity::Entity(Game *game) 
    : m_game(game),                                         // Initialise members
    m_id(m_game->g_idGenerator->generateNewID())            // Generate unique ID                       
{
    m_game->m_entities.push_back(std::shared_ptr<Entity>(this));
}

我遇到的主要问题是,一旦Game :: loadContent()方法完成,就会为Entity类调用析构函数 . 这会破坏存储在列表中的* shared_ptr *,并在尝试调用任何虚拟方法时发生错误 .

我想边界指针一直存在,直到我说删除 . 如果没有将Boundary分配给堆,有没有办法做到这一点?

编辑

回应使用const&Game的建议

看来我必须将我的Entity Headers 更改为以下内容

Entity.h

#pragma once

#include <glm\glm\glm.hpp>

#include "Game.h"

// Forward declarations
class Game;

class Entity
{
public:
    // Make destructor virtual as this is a base class
    virtual ~Entity(void);

    // '= 0' means pure virtual function (like 'abstract' in C#)
    // This means they do not have to be declared in the source file '.cpp'
    virtual void draw(float dt) = 0;
    int getID();                                
    virtual glm::vec3 getPosition() = 0;
    virtual void update(float dt) = 0;          

protected:
    explicit Entity(const Game &game);          // Abstract base constructor

    Game m_game;
    int m_id;                                   // Unique ID
};

Game m_game 不是将Game类的实例分配给堆栈吗?如果要表示引用,应如何在 Headers 中声明?

编辑2

如果我在基础实体类 const Game &m_game 中存储对Game类的受保护引用,我似乎无法在派生类中访问Game类 g_wireShapeDrawer 的全局成员 .

class Game
{
public:
    GL_WireShapeDrawer g_wireShapeDrawer;

    Game(void);
    ~Game(void);

    void init();
    void draw(float dt);
    void handleInput(float dt);
    void loadContent();
    void update(float dt);
};

例如,我在尝试访问派生的Boundary类源的draw方法中的全局成员时遇到以下错误

void Boundary::draw(float dt)
{
    m_game.g_wireShapeDrawer.drawPlane(glm::vec3(0, 1, 0), 0.0f, glm::vec4(1, 1, 1, 1));
}

错误C2662:'GL_WireShapeDrawer :: drawPlane':无法将'this'指针从'const GL_WireShapeDrawer'转换为'GL_WireShapeDrawer&

为什么是这样?

2 回答

  • 2

    永远不应从任何 Entity 或派生类中删除 Game 对象 . 它应该是应用程序关闭之前要解除分配的最后一件事 .

    您应该将其作为 Game& 传递给 Entity 类 . 为什么?因为你只有一个 Game 的实例,所以不需要重置它指向的内容,它总是应该有效(因为游戏将在 Entity 对象之前存在) .

    另一种选择是在 Game 类中实现 Singleton Pattern ,并像这样访问 Game::GetInstance().m_dynamicsWorld->removeRigidBody(m_body);

    根据您的编辑,您可以使用初始化列表创建 Entity . 这样你可以存储const成员,如下所示:

    class Entity
    {
      protected:
        explicit Entity(Game &game) : m_game(game) {}
      private:
        Game& m_game;
    }
    
  • 2

    你的设计有缺陷 . 您需要明确说明(通过您的设计)谁拥有指针 . 如果 Entity 拥有指针,那么它应该在你的析构函数中释放它(更好的是;只需将它包装在_434116中) . 如果它不拥有指针,那么就不要解除分配 .

    你不可能两种方式 . 你正在使用 shared_ptr ,这意味着多个"owners",并且一旦完成最后一个所有者,内存将被释放 . 同样,你需要清楚地设计谁拥有这个记忆 .

    从您的代码来看,似乎 Entity 并不真正拥有 Game* . 它出于实现原因需要它,但不应对其解除分配负责 .


    在旁注中,您违反了The Rule of Three .

相关问题