在迭代另一个向量时,从矢量中删除指针

时间:2014-12-14 00:51:45

标签: c++ pointers vector

我尝试了很多其他类似的问题,但没有一个能帮助我。我的问题如下: 我有3个指向我结构的指针向量:vector<state*>其中state是我的结构类型。我要做的是从vectorCheckvectorOpen中移除vectorClosed中的状态。关键是,它有时工作正常,有时不工作。根据CodeBlocks debugger,这似乎是一个问题,但我不知道要克服这个问题。我一步一步地调试了我的程序,在某些时候,vectorCheck的状态并没有被移除,尽管它在vectorClosed中。

Iforrating由2 for for循环:

vector<state*> vectorOpen;
vector<state*>::iterator itOpen;
vector<state*> vectorClosed;
vector<state*>::iterator itClosed;
vector<state*> vectorCheck;
vector<state*>::iterator itCheck;

for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end(); itCheck++) {
        for(itOpen = vectorOpen.begin(); itOpen != vectorOpen.end(); itOpen++) {
            if ((*itCheck)->player->x == (*itOpen)->player->x &&
               (*itCheck)->player->y == (*itOpen)->player->y &&
               (*itCheck)->box[0].x == (*itOpen)->box[0].x &&
               (*itCheck)->box[0].y == (*itOpen)->box[0].y) {
                cout << "erasing as in open " << (*itCheck)->player->x << "   " << (*itCheck)->player->y << "   " << (*itCheck)->box[0].x << "   " << (*itCheck)->box[0].y << endl;
                vectorCheck.erase(itCheck);
            }
        }
    }

    for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end(); itCheck++) {
        for(itClosed = vectorClosed.begin(); itClosed != vectorClosed.end(); itClosed++) {
            if((*itCheck)->player->x == (*itClosed)->player->x &&
               (*itCheck)->player->y == (*itClosed)->player->y &&
               (*itCheck)->box[0].x == (*itClosed)->box[0].x &&
               (*itCheck)->box[0].y == (*itClosed)->box[0].y) {
                cout << "erasing as in closed " << (*itCheck)->player->x << "   " << (*itCheck)->player->y << "   " << (*itCheck)->box[0].x << "   " << (*itCheck)->box[0].y << endl;
                vectorCheck.erase(itCheck);
            }
        }
    }

vectorCheck的最大尺寸为3.要解释我的意思,picture 我在这里谈论绿色矩形的状态(3 1 2 4)。为什么它不像蓝色矩形(2 2 2 4)中的状态被移除?它应该被移除,因为此状态已经出现在vectorClosed(上面的代码)中。

我做错了什么?这不是程序的第一次迭代,它发生在第6或第7循环中。

此外,这可能导致我的程序稍后崩溃。

2 个答案:

答案 0 :(得分:2)

正如我在评论中提到的,问题是你继续使用迭代器来删除你删除的元素。 std::vector::erase(i)使itCheck迭代器失效。

我们可以通过利用像std::remove_if这样的C ++算法来解决这个问题。它可能会使代码看起来更复杂,但您会发现这种编码风格可以让您重用逻辑片段,从而提高代码的可读性和可维护性。

首先,让我们编写一个函数来进行你需要的相等比较。

struct states_are_equal :
    public std::binary_function<state const *, state const *, bool>
{
    bool operator()(state const * a, state const * b) const {
        return a->player->x == b->player->x &&
               a->player->y == b->player->y &&
               a->box[0].x == b->box[0].x &&
               a->box[0].y == b->box[0].y;
    }
};

现在我们需要一个谓词,如果在另一个容器中找到给定的项目,它将返回true。如果你不熟悉算法库,这部分可能有点难以理解。

template <typename Iterator, typename Comparer>
struct is_in_container_func :
    public std::unary_function<
        typename std::iterator_traits<Iterator>::value_type const &,
        bool
    >
{
    is_in_container_func(Iterator begin, Iterator end, Comparer cmp)
        : it_begin(begin), it_end(end), comparer(cmp) { }

    bool operator()(argument_type i) const {
        return std::find_if(it_begin, it_end, std::bind1st(comparer, i)) != it_end;
    }

private:
    Iterator it_begin;
    Iterator it_end;
    Comparer comparer;
};

// This is just a helper to allow template type deduction; its only purpose is to
// allow us to omit the types for Iterator and Comparer when constructing an
// is_in_container_func object.
template <typename Iterator, typename Comparer>
is_in_container_func<Iterator, Comparer> is_in_container(
    Iterator begin, Iterator end, Comparer cmp)
{
    return is_in_container_func<Iterator, Comparer>(begin, end, cmp);
}

现在我们可以将所有这些部分与std::remove_if

放在一起
std::vector<state*> vectorOpen;
std::vector<state*> vectorClosed;
std::vector<state*> vectorCheck;

// Make one pass, removing elements if they are found in vectorOpen.
std::vector<state*>::iterator new_end = std::remove_if(
    vectorCheck.begin(), vectorCheck.end(),
    is_in_container(vectorOpen.begin(), vectorOpen.end(), states_are_equal()));

// Make another pass, removing elements if they are found in vectorClosed.
new_end = std::remove_if(
    vectorCheck.begin(), new_end,
    is_in_container(vectorClosed.begin(), vectorClosed.end(), states_are_equal()));

// std::remove_if just swaps elements around so that the elements to be removed are
// all together at the end of the vector, and new_end is an iterator to the first
// one.  So, finally, we just need to remove the range [new_end, end()).
vectorCheck.erase(new_end, vectorCheck.end());

答案 1 :(得分:0)

erase调用使传递给它的迭代器无效。它将向量中的元素向左移动一个位置,并在移除后的元素后返回一个迭代器。因此,如果erase已执行,您应该增加迭代器。像这样:

for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end();) { // no increment
    bool found = false;
    for(itOpen = vectorOpen.begin(); itOpen != vectorOpen.end(); itOpen++) {
        if ((*itCheck)->player->x == (*itOpen)->player->x &&
           (*itCheck)->player->y == (*itOpen)->player->y &&
           (*itCheck)->box[0].x == (*itOpen)->box[0].x &&
           (*itCheck)->box[0].y == (*itOpen)->box[0].y) {
            cout << "erasing as in open " << (*itCheck)->player->x << "   " <<    (*itCheck)->player->y << "   " << (*itCheck)->box[0].x << "   " << (*itCheck)->box[0].y << endl;
            itCheck = vectorCheck.erase(itCheck);
            found = true;
            break; // found element and erased it. back to outer loop
        }
    }

    if (!found) ++itCheck;  // didn't find it, need to increment
}