【问题标题】:Pointer sets to null-pointer when going out of function退出功能时指针设置为空指针
【发布时间】:2013-05-24 18:17:19
【问题描述】:

我有一个我不明白的阻塞问题。一般来说,我正在制作一种蚁丘模拟。内部有一个主要通道,分为几段,蚂蚁可以从其中一些段进入房间。所有这三个类(通道、段、腔室)都有一个共同点——当前访问它们的蚂蚁的集合。所以有一个抽象类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-&gt;items.back() 都指向这个对象的一些内存。但是当我运行类似的代码时:

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

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

我完全无法理解发生了什么,尤其是putItemantEnter 实际上都在做同样的事情: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。

【问题讨论】:

  • 你检查chamber-&gt;antEnter(ant));的返回值不是false吗?由于我们没有简短的、自包含的示例,因此很难确定问题:sscce.org
  • 在antEnter中,itemCapacity和additionalCapacity的值是多少?你真的想在 antEnter 中使用 itemCapacity 吗?
  • @Shafik Yaghmour - 我做到了。事实并非如此。当我测试它时,两个向量都是空的,两个容量都更高 - 例如10 + 5。如您所见,我试图简化示例,但我的尝试失败了 :)
  • @Sushi271 好的,您可以将您的代码简化为重现问题的 SSCCE 吗?似乎问题出在我们没有的代码部分。
  • @AndyThomas-Cramer - 我认为这与案例无关;但是如果你问:这个想法是,你可以用最多 itemCapacity 限制的物品填充房间,但是必须为蚂蚁留出一些空间,这样它们才能进来。但是如果物品比 itemCapacity 少,那么蚂蚁就会更多可以进来。所以itemCapacity + additionalCapacity = totalCapacity,蚂蚁和物品都不能超过。但是蚂蚁本身没有其他限制,不像物品。

标签: c++ pointers vector null


【解决方案1】:

天哪,我真是瞎了眼……

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

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

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

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

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

【讨论】:

  • 这是进行 SSCCE 的要点之一,我猜您可能会自己解决。在许多情况下,尝试在较小的示例中演示错误会导致找出问题。
猜你喜欢
  • 2017-11-09
  • 2012-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-02
  • 2021-06-29
相关资源
最近更新 更多