我尝试了很多其他类似的问题,但没有一个能帮助我。我的问题如下:
我有3个指向我结构的指针向量:vector<state*>
其中state
是我的结构类型。我要做的是从vectorCheck
或vectorOpen
中移除vectorClosed
中的状态。关键是,它有时工作正常,有时不工作。根据CodeBlocks ,这似乎是一个问题,但我不知道要克服这个问题。我一步一步地调试了我的程序,在某些时候,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循环中。
此外,这可能导致我的程序稍后崩溃。
答案 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
}