擦除CPP中的重叠对象
Erasing Overlapping Objects In CPP
我有一个名为shape1->overlaps(shape2)
的方法和一个形状向量。
我必须擦除在我的形状向量中重叠的所有形状。我目前不知道如何做到这一点,我不确定为什么这个代码不起作用。
for (vector<Shape *>::iterator it = shapes->begin(); it != shapes->end();){
for (vector<Shape *>::iterator jt = it + 1; jt != shapes->end();){
// If the shapes are not the same
if (*it != *jt){
// Check if they overlap, if they do remove them.
if ((*it)->overlaps(*jt)){
// Print the overlapping shapes
printShapeInfo(*jt);
jt = shapes->erase(jt);
} else {
++jt;
}
} else {
++jt;
}
}
printShapeInfo(*it);
it = shapes->erase(it);
++it;
}
我得到的错误是:矢量迭代器在Visual Studio中运行时不可递增。
一些建议:
首先,对于外部循环,使用常规循环索引,而不是迭代器。
原因是您在循环时更改了向量的内容和大小。更改内容意味着您现在用来循环的迭代器将无效。在这方面,使用普通索引要容易得多。
其次,对于内部循环,去掉它,并使用一个(或两个)算法函数来找出被擦除的内容。所以本质上,你有一个循环。
这里有一个版本(未测试),可能会模仿你想要做的事情。注意,我不得不模拟你的类,试图展示正在发生的事情:
#include <vector>
#include <algorithm>
//...
class Shape
{
public:
bool overlaps(Shape *s) { return true; }
bool operator==(const Shape& s) { return true; }
bool operator!=(const Shape& s) { return false; }
};
void printShapeInfo(Shape& s) {}
void foo(std::vector<Shape*>* shapes)
{
// use a regular index here
for (size_t i = 0; i < shapes->size(); ++i)
{
// get our starting point
auto it = shapes->begin() + i;
// point to the next item after the i'th item.
auto it2 = shapes->begin() + i + 1;
// partition the objects. Collided ones go on the left of the partition,
// others go to the right of the partition.
auto div =
std::stable_partition(it2, shapes->end(),
[&](Shape* s){ return (*s != *(*it2))?s->overlaps(*it2):false;});
// check if there is anything on left side of partition
if ( it2 != div )
{
// for each of the collided ones, print stuff out
std::for_each(it2, div, [&](Shape *s){ printShapeInfo(*s); });
// we're done with them, now erase them.
shapes->erase(it2, div);
// also erase the iterator we collided with
shapes->erase(it);
}
}
}
做了什么?我们使用std::stable_partition将碰撞的元素移动到向量的一侧,其中div
是碰撞项目和未碰撞项目之间的分界线。
这样我们就有机会为每个项目调用printShapeInfo
。然后,我们最终使用vector::erase
将它们从向量中移除。
请注意,迭代器无效错误可以通过此实现消除(希望如此)。当给出正确的参数时,算法的功能只是"工作"。您也不会看到试图重新封装迭代器的棘手代码。对于序列容器,几乎没有理由编写循环来遍历容器,同时从容器中擦除。
同样,这并没有经过测试,但你应该了解所做的事情的要点。
我认为唯一的问题是外循环底部的it++;
。
考虑一下当向量中只剩下一个形状时会发生什么。你到达循环的底部并擦除最后一个形状。这将it
更新为shapes->end()
。然后不能再次递增it
,因为这会偏离数组的末尾。在生产代码中,这将是未定义的行为。在调试代码中,Visual C++似乎提供了一些检测。
删除it++;
语句,您将始终指向下一个形状(如果有的话),它似乎就是您想要的。
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- CMake-按正确顺序将项目与C运行时对象文件链接
- 空基优化子对象的地址
- 将对象数组的引用传递给函数
- 你能重载对象变量名本身返回的内容吗
- C++使用整数的压缩数组初始化对象
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 将对象移动到std::shared_ptr
- 代理对象的常量正确性
- Ardunio UNO解决了多个重叠的定时器循环
- 提升 ASIO 无法识别计时器对象
- 将Ref对象作为类成员
- 将包含C样式数组的对象初始化为成员变量(C++)
- USB-HID 读/写(重叠)等待单个对象不返回C++
- 擦除CPP中的重叠对象
- 用2个着色器渲染两个重叠的2D对象
- malloc'd 内存重叠由 std::make_shared 创建的对象
- 2D矢量,数组中的重叠和不同类型的对象
- 在Opengl中渲染.重叠的对象