如何在一步中从多图中删除多个项目?

时间:2014-01-05 10:20:15

标签: c++ iterator multimap

我使用迭代器来移除物品,我想在每一步中擦除地图中的第一项和第二项。

这是代码(此代码是霍夫曼代码的一部分)

std::multimap<float, node *> ::iterator first, second;
first = floattnode.begin();
second = ++first;
while (floattnode.size() != 0) { //floattnode is a multimap mapping frequency to node
    root = new node((*first).first + (*second).first, '-');
    root->left = new node(((*first).second), 0);
    root->right = new node(((*second).second), 1);

    floattnode.erase(first);
    floattnode.erase(second);//here i have problem

    first = floattnode.begin(); //check
    floattnode.insert(std::pair<float, node *>(root->freq, root));
    first = floattnode.begin();
    second = ++first;
}

当迭代器删除第一个项目时,它无法访问要删除的第二个项目,如何删除这两个项目?

2 个答案:

答案 0 :(得分:4)

second=++first;

在这里,您不仅要将迭代器分配给second的第二个元素,而且还要在first中使用迭代器,因为++是增量运算符,它递增操作数。似乎没有multimap迭代器的加法运算符。因此,在再次分配second之后,您必须减少迭代器:

second = (++first)++;

这将首先递增first并将其返回second,之后它将再次递增。或者分配给second并在之后递增:

second = first;
second++;

或更短:

(second = first)++;

无论如何,您应首先检查容器中是否至少有两个元素。如果没有元素,那么您将尝试递增first == floattnode.end(),调用未定义的行为。 (我的设置实际上给了我一个无限循环来尝试这个,另见Strange behavior with std::map::iterator's postincrement

while (floattnode.size() != 0) {

您正在每个循环回合中创建new的新对象,并将其指针指定给root,稍后将指针插入floattnode,但在其中一个中删除它们循环再次转动。所以你在某些时候松开了对创建对象的所有引用。既然你也从不在它们上面调用delete,你就会在那里泄漏记忆。

由于在每次循环运行结束时向floattnode添加元素,因此floattnode.size()在循环条件检查时永远不会为零。这是一个无限循环。

root=new node((*first).first+(*second).first,'-');

如果floattnode.size() == 1这将被执行,second将被取消引用,尽管它指向地图的最后一个元素。这会导致未定义的行为。

而不是(*first).first,您应该使用first->first来提高可读性。 (它也是这样)。

floattnode.erase(first);
floattnode.erase(second);//here i have problem

由于我在开头提到的错误,您试图两次擦除相同的迭代器。通常,如果容器被修改,容器的迭代器可能会变得无效,所以如果你想确保这不会影响你使用:

floattnode.erase(floattnode.begin());
floattnode.erase(floattnode.begin()); // Notice this is now the originally second element because the first one was erased.

然而,对于multimap,根据此处的答案Iterator invalidation rules调用erase,似乎只有被删除的迭代器无效。在这种情况下,你可以使用原始代码。

因为您只检查容器大小是否大于零,所以如果大小正好是1并且您尝试擦除第二个元素(即floattnode.end(),则指向未定义的行为,指向在最后一个元素后面。)

second = ++first;

与开头时的错误相同。

答案 1 :(得分:0)

我从不修改集合,列表或地图。我总是创建一个新的并循环旧的,将我想要的条目添加到新的条目中,省略我要删除的条目。

我尝试了解删除到位和迭代器的情况,并认为这对我来说太难了,而且任何人都跟着我。