【问题标题】:Deleting pointers objects in std list删除标准列表中的指针对象
【发布时间】:2014-08-03 10:14:26
【问题描述】:

我有一个 std::listEntity 对象(屏幕上的对象)。在一个类EntityContainer 中,我有一个指向不同实体的指针列表。当 EntityContainer 被破坏时,我希望该列表中的所有实体也被破坏。我该如何做到这一点,同时避免导致删除列表成员的迭代器错误?

EntityContainer::~EntityContainer()
{
    // Destroy children
    int numChildren = children.size();
    for (int i = 0; i < numChildren; i++)
    {
        Entity*& child = children.back();
        delete child;
    }
}

上述导致 std::list::clear() 中的空指针访问冲突,在 EntityContainer 的销毁期间调用,因为它是该对象的成员变量。我相信这是因为我已经删除了它列表中的对象,所以当然它会在删除它们时尝试访问它们。但是,我的问题是,如果我只是离开它,并允许 clear() 列表而不显式删除其中的对象,则永远不会调用它们的析构函数。我只能假设这是因为列表只破坏了列表中的指针,而不是指针指向的对象。不过,这主要是假设-我可能是错的。你会怎么做?

【问题讨论】:

  • 如果您需要指针,请使用智能指针。
  • children 是如何定义的? std::list&lt;Entity *&gt;?
  • 没错 nneonneo。
  • 您的访问违规不是由于列表被破坏。

标签: c++ list pointers c++11


【解决方案1】:

假设children被定义为

std::list<Entity *> children;

你可以delete元素使用:

for(auto&& child : children) {
  delete child;
}
children.clear(); // not really needed since this code is in the destructor

这里没有使任何迭代器失效的问题,因为您实际上并没有从list 中删除任何元素,只是破坏了列表元素指向的对象。在for 语句完成后,list 仍将包含相同数量的元素,只是它们此时将指向无效内存。


但实际上,不要使用原始指针容器。将children定义为

std::list<std::unique_ptr<Entity>> children;

然后你就可以摆脱析构函数的定义了。

【讨论】:

  • 这正是我想要的,谢谢。是的,我后来意识到这个循环是愚蠢的——主要是由于太多的改变和混合了旧的实现。无论如何,看起来智能指针是要走的路。干杯。
【解决方案2】:

std::list&lt;Entity *&gt; 在销毁期间不会尝试访问任何指向的对象。

您的重复删除代码似乎有误。您应该做的只是遍历列表并删除所有内容:

for(Entity *ptr : children) {
    delete ptr;
}

然后让列表进行清理(释放内部指针列表)。

【讨论】:

  • 它不喜欢那样。抛出“列表迭代器不兼容”。不知道为什么。我明白你现在的意思了,关于列表迭代。恐怕上面是一些稍微过时的拼接代码。确切的删除方法发生了很大变化,但问题仍然存在。它似乎也适用于由您的解决方案引起的错误。
【解决方案3】:

您的循环不会对列表中的每个指针调用 delete。它只在最后一个指针上重复调用 delete 。这就是您的访问违规的原因。

delete 不会从 list 中删除任何内容,因为它对此一无所知。

你需要做类似的事情

for(auto itr = children.begin(); itr != children.end(); ++itr)
{
    Entity* child = *itr;
    delete child;
}

或者任何你喜欢的循环语法。

或者,您可以将其设为 liststd::unique_ptr&lt;Entity&gt;,以便在清除列表或删除条目时自动管理释放。

【讨论】:

    【解决方案4】:

    您的循环出现错误主要是因为这个

    int numChildren = children.size();
    for (int i = 0; i < numChildren; i++)
    {
        Entity*& child = children.back(); // this always returns the last element on the last, it does not remove it.  You are trying to delete an already deleted pointer
        delete child;
    }
    

    就像上面建议的那样,试试类似的东西

    for(auto itr = children.begin(); itr != children.end(); ++itr)
    {
        Entity* child = *itr;
        delete child;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-20
      • 1970-01-01
      • 2011-05-02
      • 2016-03-18
      • 2012-09-10
      • 2017-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多