c++ refer to consecutive values with iterator - c++

I want to calculate values of w, being the distance between two points, iteratively. In my Aclass i have members like x, y and this w. So I use Pitagoras Theorem, but how to do it smoothly using iterators? This is my try, but I don't know how using iterator reference to the "previous than pointed" value.
Please help :)
Aclass temp;
for (ars::cClassC::iterator it = New_Diff.begin(); it != New_Diff.end(); it++)
{
temp.w = sqrt(((it->getX()-(it->getX()-1))^2+((it->getY()-(it->getY()-1)));
New_Diff.push_back(temp);
}

Just save the previous element:
ars::cClassC::iterator it_prev = New_Diff.end();
for (ars::cClassC::iterator it = New_Diff.begin(); it != New_Diff.end(); it++) {
if (it_prev != New_Diff.end()) {
//do the stuff here, now you have the two elements
}
it_prev = it;
}

Related

Removing an object from vector while iterating through it

I'm new to C++ so I'm having trouble figuring out how to best remove an object from a vector while still iterating through it.
Basically, I need to iterate through two vectors. For every item, if the ID's match, I can remove them.
//For every person, check to see if the available bags match:
for(std::vector<Person>::iterator pit = waitingPeopleVector.begin(); pit != waitingPeopleVector.end(); ++pit) {
for(std::vector<Bag>::iterator bit = waitingBagsVector.begin(); bit != waitingBagsVector.end(); ++bit) {
int pId = pit->getId();
int bId = bit->getId();
if(pId == bId){
//a match occurs, remove the bag and person
}
}
}
Working with iterators is a bit confusing, I know I can use the .erase() function on my vectors, but I can't really pass pit or bit. Any help appreciated. Thanks
From the standard:
The iterator returned from a.erase(q) points to the element
immediately following q prior to the element being erased. If no such
element exists, a.end() is returned.
I would use it in something like using the erase method:
std::vector<Person>::iterator pit = waitingPeopleVector.begin();
std::vector<Bag>::iterator bit = waitingBagsVector.begin();
while (pit != waitingPeopleVector.end())
{
bool didit;
while (bit != waitingBagsVector.end())
{
didit = false;
if (pit->getId() == bit->getId() && !didit)
{
bit = waitingBagsVector.erase(bit);
pit = waitingPeopleVector.erase(pit);
didit = true;
}
else
{
++bit;
}
}
if (didit)
continue;
else
++pit;
}
Using the erase-remove idiom will achieve this objective, the below offers an (untested) way using lambdas and <algorithm> functions to remove elements from wPL which have the same ID as wBL. It shouldn't be too much effort to extend this to both lists. Note, we have used std::list instead of std::vector for faster removal.
std::list<Person> wPL;
std::list<Bag> wBL;
//...
wPL.erase(std::remove_if(wPL.begin(), wPL.end(),
[&wBL](auto x) { return std::find_if(wBL.begin(), wBL.end(), [](auto y)
{ return x.getId() == y.getId();); }), wPL.end() };

segmentation fault in iterator

I have created a multimap for my road points. The key refers to the road number and the values are vec3 points that make up the road.
I am trying to iterate through the values of each key point and create a road segment at each point on the road (except the last), adjust the values to be on the road points and then store them in a std::vector.
The RoadSegment constructor creates 6 vec3 points and pushes them onto a std::vector.
I have a segmentation fault in the line marked in bold
[for(mapIt = it.first; mapIt != it.second; ++mapIt)]
When i take out the lines creating the new objects and pushing them onto the std::vector it works fine.
Can anyone tell me what the problem is / a solution to the problem??
Many thanks in advance
std::vector<glm::vec3>::iterator SegIt;
for(int i = 0; i < m_genRoads->getKeyValueData().size(); i++)
{
int numberDesired = m_genRoads->getMultimapData().count(i) - 1;
std::multimap<int, glm::vec3>::iterator mapIt;
std::pair<std::multimap<int, glm::vec3>::iterator, std::multimap<int, glm::vec3>::iterator> it;
it = m_genRoads->getMultimapData().equal_range(i);
for(mapIt = it.first; mapIt != it.second; ++mapIt)
{
int distance = std::distance(it.first, mapIt);
if(distance != numberDesired)
{
RoadSegement* roadSegmentPointer = new RoadSegement();
// FUNCTIONS TO ADJUST COORD VALUES TO MATCH THE ROAD POINTS
m_segmentArray.push_back(roadSegmentPointer);
}
else
{
continue;
}
///SOME BUFFER BINDING STUFF
The issue seems to be that you're using iterators that do not exist, all due to returning a temporary object.
it = m_genRoads->getMultimapData().equal_range(i);
Since getMultiMapData() returns a copy of the multimap, that multimap is gone after the line is executed, thus rendering any iterators invalid.
One solution is to return a reference to the multimap, not a new copy of the multimap.
std::multimap<int, glm::vec3>& GenerateRoads::getMultimapData() { return m_roadsMultimap; }

object from vector with structs

i 'm pretty new to c++, can you help me with pointers ? i have a struct
struct Slice
{
Slice(): {}
SliceObj *slObj;
};
and vector:
std::vector<Slice> slices;
So on mouce touch i want to take this object to change his public var:
for (vector<Slice>::iterator it = slices.begin(); it != slices.end(); ++it) {
Slice slice0 = slices[0];
SliceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}
And of coure of course when in drag method i make : slObj->rect.x = x+0.1;, it doesn't make anything good.
Please, help me with this, i can't understand how to carefully get obj with * from another object from vector and then carefully change it's param;
Trouble is in "how to carefully get SliceObj from slice0", not address of var, but this instance.
So here i need to get slObj param, that in future i can make slObj.rect.x = 1;
UPDATE:
when i make slObj->drag method i always see only strange number like:
but then, when glutPostRedisplay called and it's redraw on method
void SliceObj::draw(SliceObj *slObj)
then it's all good!
You should access the element through the iterator:
for (vector<Slice>::iterator it = slices.begin(); it != slices.end(); ++it) {
Slice& slice0 = *it //Get the element using iterator (Note the reference, is to avoid copy)
SliceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}
However, if you have a C++11 capable compiler, you could simplify things using range-based for loop:
for( auto& slObj : slices )
{
liceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}
You need to use the iterator to get the element from the vector. Here you are always getting the first element. Try this:
for (vector<Slice>::iterator it = slices.begin(); it != slices.end(); ++it) {
Slice slice0 = *it //Get the element using iterator
SliceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}

C++ double iterator loop for collision detection

First things first, I'm very new to C++! So I've got a standard list of objects representing elements in 2d space, and I want to do some basic collision detection. My first idea (coming from a mostly Java background...) is to compare each object with each other object, calling an function to check for intersection on each pair or objects. This would have been simple in Java, taking the first item of the ArrayList, comparing it with the second, third, etc. then taking the second item, comparing it with the third, fourth, etc. This is the approach I took with the problem in C++, but I'm using an iterator (rather than direct element access like I'd do in Java), but iterators are meant to be used linearly, right? So direct access isn't suitable.
So my question is how do I perform this algorithm? I'm also reasonably sure this isn't the best way to do (very basic) collision detection, so any advice on that would be welcomed too. Here's my (non-working) code.
for (list<Box>::iterator p = mBoxes.begin(); p != mBoxes.end(); p++) {
for (list<Box>::iterator q = mBoxes.begin() + p); q != mBoxes.end(); q++) {
if (p->isIntersecting(q)) {
p->changeDirection();
q->changeDirection();
}
}
}
This should illustrate the method I'm attempting, but of course my try of mBoxes.begin() + p doesn't work!
EDIT: Responding to multiple comments.
for (list<Box>::iterator p = mBoxes.begin(); p != mBoxes.end(); ++p) {
for (list<Box>::iterator q = p); q != mBoxes.end(); ++q) {
if (p==q) continue;
if (p->isIntersecting(*q)) {
p->changeDirection();
q->changeDirection();
}
}
}
The list class is a linked list, you cannot directly index into it. Also, iterators are not indices, + just doesn't makes any sense.
However, in theory, you should be able to copy an iterator, if you change q = mboxes.begin() + p into q = p it should set q to be an iterator pointing to the same location of p, and that may just solve your problem.
for (list<Box>::iterator p = mBoxes.begin(); p != mBoxes.end(); p++) {
for (list<Box>::iterator q = p, q++; q != mBoxes.end(); q++) {
if (p->isIntersecting(q)) {
p->changeDirection();
q->changeDirection();
}
}
}
the q++ should simply skip the current element so you don't compare an item against itself.
Something like this should work:
for (int p = 0; p < mBoxes.size(); ++p)
{
for (int q = 0; q < mBoxes.size(); ++q)
{
if (p == q)
{
// don't compare for collision against itself
continue;
}
if (mBoxes[p]->isIntersecting(mBoxes[q]))
{
mBoxes[p]->changeDirection();
mBoxes[q]->changeDirection();
}
}
}
However, one problem with this is that as you iterate through you'll compare p intersect q and also q intersect p meaning that if they do intersect they'll change direction twice putting them back in the same direction each time. So some extra logic would be needed to avoid this.

Erasing an element from the vector during iteration c++

I wrote this method to find the minor of a sparse matrix:
SpMatrixVec SparseMatrix::minor(SpMatrixVec matrix, int col) const{
SpMatrixVec::iterator it = matrix.begin();
int currRow = it->getRow();
int currCol = col;
while(it != matrix.end()) {
if(it->getRow() == currRow || it->getCol() == currCol){
matrix.erase(it);
}
// if we have deleted an element in the array, it doesn't advance the
// iterator and size() will be decreased by one.
else{
it++;
}
}
// now, we alter the cells of the minor matrix to be of proper coordinates.
// this is necessary for sign computation (+/-) in the determinant recursive
// formula of detHelper(), since the minor matrix non-zero elements are now
// in different coordinates. The row is always decreased by one, since we
// work witht he first line, and the col is decreased by one if the element
// was located after 'col' (which this function receives as a parameter).
//change the cells of the minor to their proper coordinates.
for(it = matrix.begin(); it != matrix.end(); it++){
it->setRow(it->getRow()-1);
int newY;
newY = (it->getCol() > col) ? it->getCol() + 1 : it->getCol();
it->setCol(newY);
}
return matrix;
}
Now, i'm probably doing something wrong, because when reaching the second interation of the while loop, the program crashes.
The basic idea was to go over the vector, and see if it is the relevant coordinate, and if so - to delete it. I increment the iterator only if there was no deletion (and in this case, the vector should update the iterator to be pointing the next element..unless i got these things wrong).
Where is the problem?
Thanks a lot.
erase() invalidates your iterator.
You must update it using the return value of erase() for the loop to work:
while(it != matrix.end()) {
if(it->getRow() == currRow || it->getCol() == currCol){
//matrix.erase(it);
it = matrix.erase(it); // Here is the change
}
// if we have deleted an element in the array, it doesn't advance the
// iterator and size() will be decreased by one.
else{
//it++;
++it; // ++i is usually faster than i++. It's a good habit to use it.
}
}
erase invalidates your iterator. Do it = matrix.erase(it) instead.
You can't change a collection while you're iterating between its elements.
Use another temp collection to store the partial results.
edit: Even better, use a functor to delete elements: remove_if
You write the condition.