将本地对象推送到列表中

时间:2014-12-31 16:53:38

标签: c++ marmalade

我有一个班级

class Invader
{
public:
    Invader();
    ~Invader();
public:
    void Init(InvaderTypes invadertype, CIw2DImage *AlienImage);
    void Update(float dt);
    void Render();
    void SetAlienImage(CIw2DImage *image){ ImageAlien = image; }

    void        setVisible(bool show)       { Visible = show; }
    bool        isVisible() const           { return Visible; }


    Iw2DSceneGraph::CSprite         *AlienSprite;
    Iw2DSceneGraph::CAtlas          *AlienAtals;
    CIw2DImage                      *ImageAlien;
    std::list<Bullet*>              *Bullets;
    CIwFMat2D                       Transform;              // Transform matrix

    bool                             Visible;                // Sprites visible state
    bool                             Canfire;
};


void Invader::Init(InvaderTypes invadertype, CIw2DImage *AlienImage)
{
    if (invadertype == InvaderTypes::TOP_ALIEN)
    {
        //SetAlienImage(AlienImage);
        mImageAlien = AlienImage;
        // Create EnemyTop atlas
        int frame_w = (int)(mImageAlien->GetWidth() / 2);
        int frame_h = (int)(mImageAlien->GetHeight());
        AlienAtals = new CAtlas(frame_w, frame_h, 2, mImageAlien);
        AlienSprite = new CSprite();
        AlienSprite->m_X = 0;
        AlienSprite->m_Y = 0;
        AlienSprite->SetAtlas(AlienAtals);
        AlienSprite->m_W = (float)AlienAtals->GetFrameWidth();
        AlienSprite->m_H = (float)AlienAtals->GetFrameHeight();
        AlienSprite->m_AnchorX = 0.5;
        AlienSprite->SetAnimDuration(2);
    }
    else if (invadertype == InvaderTypes::MIDDLE_ALIEN)
    {

    }
    else if (invadertype == InvaderTypes::LAST_ALIEN)
    {

    }


    Visible = true;
    Bullets = new std::list<Bullet*>();
    Canfire = true;
}



Invader::Invader()
    {

    }
    Invader::Invader(const Invader&other)
    {
        AlienAtals = new CAtlas();
        AlienSprite = new CSprite();
        *AlienAtals = *other.AlienAtals;
        *AlienSprite = *other.AlienSprite;
    }

我尝试通过以下方式初始化它:

list<Invader> *invaders = new list<Invader>();

    int spacing = 10;
for (int i = 0; i < 5; i++)
{
    Invader invader;
    invader.Init(TOP_ALIEN, gameResources->getAlienImageTop());
    invader.AlienSprite->m_X = 50 + spacing;
    invaders->push_back(invader);
    spacing += 50;
}

将对象入侵者推送到列表后,最后入侵者列表保存未初始化的指针。所有的指针都丢失了引用。我想知道为什么 ?

2 个答案:

答案 0 :(得分:2)

我认为问题出在~Invader()中。让我们简化示例:

struct A {
    int* p;
    A() { p = new int(42); }
    ~A() { delete p; }
};

A只管理一个指针。当A超出范围时,该指针将被删除。现在,当我们这样做时会发生什么:

list<A> objs;
{
    A newA;
    objs.push_back(newA);
    // newA deleted here
}
// objs has one element... but its pointer has been deleted!

问题是复制Apush_back()执行)只执行浅拷贝:我们复制指针。但由于A管理自己的内存,我们需要执行副本。那就是:

A(const A& rhs)
: p(new int(*(rhs.p)))
{ }

这样,复制的A赢了双删除相同的指针。使用C ++ 11,只需:

就可以更轻松地管理它
struct A {
    std::shared_ptr<int> p;
    A() { p = std::make_shared<int>(42); }
    ~A() = default; // this line not even necessary
};

此处,复制A将复制shared_ptrA的两个副本都将有一个有效的对象指向。如果您不能使用C ++ 11,您仍然可以使用boost::shared_ptr<T>来满足所有内存管理需求。如果你不能使用它,那么你必须编写一个复制构造函数来完成所有指针元素的完整副本。

或者,最简单的解决方案是让你的容器有指针:

list<A*> objs;
objs.push_back(new A);

然后&#34;浅拷贝&#34;是正确的做法,你需要做的就是记住delete最后容器中的所有内容。

答案 1 :(得分:0)

您的列表包含Invader个对象。将它们存储在列表中时,将调用Invader复制构造函数,并将变量invader副本存储在list中。

除非你定义一个拷贝构造函数,否则它将是默认的对象的浅拷贝。这可能不是你想要的。您应该编写一个显式的复制构造函数,以确保正确复制Invader

另一种解决方案是使用Invader关键字动态分配new个对象,并在列表中存储指针。如果您这样做,请务必确保在完成后在列表中的delete对象上调用Invader