0

我有一个我不明白的阻塞问题。一般来说,我正在制作一种蚁丘模拟。内部有一个主要通道,分为几段,蚂蚁可以从其中一些段进入房间。所有这三个类(通道、段、腔室)都有一个共同点——当前访问它们的蚂蚁的集合。所以有一个抽象类AntHolder,其中包含vector<Ant*>(仅显示与案例相关的成员):

    class AntHolder
    {
    protected:
        std::vector<Ant*> ants;
        /* some other members here */

    public:          
        virtual bool antEnter(Ant* ant) = 0;
        /* some other functions here */
    };

antEnter函数在派生类中的实现方式不同,但通常用于将 ant 添加到ants. 从派生类中,我对类特别感兴趣AntChamber(这里也省略了不太重要的成员):

    class AntChamber : public AntHolder
    {
    protected:
        int itemCapacity;
        int additionalCapacity;
        std::vector<Item*> items;

        bool hasFood;
        bool hasEgg;

    public:
        bool putItem(Item* item);
        virtual bool antEnter(Ant* ant);
    };

putItem函数与函数类似antEnter,但它将Item对象添加到items集合中。(物品例如食物,由蚂蚁从一个房间移动到另一个房间。)下面显示了这两个功能的实现:

    bool AntChamber::antEnter(Ant* ant)
    {
        if (items.size() + ants.size() == itemCapacity + additionalCapacity) return false;

        ants.push_back(ant);
        return true;
    }

    bool AntChamber::putItem(Item* item)
    {
        if (items.size() == itemCapacity ||
            items.size() + ants.size() == itemCapacity + additionalCapacity)
            return false;

        if (item->getItemKind() == Food) hasFood = true; // Food == enum value
        else if (item->getItemKind() == Egg) hasEgg = true; // Egg == enum value

        items.push_back(item);
        return true;
    }

您可以清楚地看到,它们几乎相同。但是当谈到它们的效果时,有一个关键的、令人惊讶的差异,这就是我的问题的核心。

假设我已经AntChamber* chamber构建了一个。当我运行以下代码时:

    Item* item = new Item(Food);
    chamber->putItem(item);

, 然后之后两者itemchamber->items.back()指向这个对象的一些内存。但是当我运行类似的代码时:

    Ant* ant = new Ant(chamber);
    chamber->antEnter(ant));

,然后ant指向对象,但chamber->ants.back()指向NULL!

我绝对无法理解发生了什么,尤其是两者putItem实际上antEnter都在做同样的事情:push_back指针,它是通过参数传递的。我已经尝试用一些更简单的代码来模拟这种情况,比如:

    class A { };
    class B { };

    class C
    {
        vector<A*> va;
        vector<B*> vb;
    public:
        A* vaBack() { return va.back(); }
        B* vbBack() { return vb.back(); }

        void addA(A* a) { va.push_back(a); }        
        void addB(B* b) { vb.push_back(b); }
    };

    int main(int argc, char** argv)
    {
        A* a = new A();
        B* b = new B();
        C* c = new C();

        cout << (unsigned int)a << endl;
        c->addA(a);
        cout << (unsigned int)c->vaBack() << endl;

        cout << (unsigned int)b << endl;
        c->addB(b);
        cout << (unsigned int)c->vbBack() << endl;

        delete c;
        delete b;
        delete a;
    }

,但它似乎工作得很好 - 没有一个指针是 0x000000。

4

1 回答 1

1

天哪,我真是瞎了眼……

我按照Shafik Yaghmour的建议做了 SSCCE,我在做的时候注意到了这个问题。

我用了一个精神上的飞跃,说,chamber->items.back()或者chamber->ants.back()是NULL,因为事实上,他们不是!但是它们在它们的类中受到保护,所以我在两个类中都编写了一个函数来获取第 i 个项目/蚂蚁。问题是这个功能。它做了一个标准的 idiotproof 保护,防止从向量的键中给出索引,但这样做是错误的:

    if (idx < 0 || ants.size() >= idx) return 0; // SHOULD BE <= !!!
    return ants[idx];

所以它总是返回 0... 在寻找这个问题时,我可能看了数百次这个方法,但从未发现任何错误(直到现在)。

愚蠢的错误...非常感谢Shafik

于 2013-05-29T14:26:54.847 回答