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

时间:2012-09-19 21:14:26

标签: c++ pointers stack heap

在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&amp; amp;的建议游戏

看来我必须将我的Entity标题更改为以下

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类的实例分配给堆栈吗?如果要表示引用,应如何在标题中声明?

编辑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);
};

例如,在尝试访问派生边界类源的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&amp;

  

为什么会这样?

2 个答案:

答案 0 :(得分:2)

您的设计存在缺陷。您需要清楚地说明(通过您的设计)谁拥有指针。如果Entity拥有指针,那么它应该像你一样在它的析构函数中释放它(更好的是,只需将它包装在std::unique_ptr中)。如果它没有指针,那么就不要解除分配。

你无法双管齐下。您正在使用shared_ptr,因此这意味着多个“所有者”,并且一旦完成最后一个所有者,内存将被取消分配。同样,你需要清楚地设计谁拥有这个记忆。

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


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

答案 1 :(得分:2)

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

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

另一个选择是在Entity课程中实施单身人士模式,并像Game

一样访问它

根据您的修改,您可以使用初始化列表创建Game::GetInstance().m_dynamicsWorld->removeRigidBody(m_body);。这样就可以存储const成员,如下所示:

Entity