i have the following situation
typedef std::array<std::array<string,9>,9>candidates;
std::vector<candidates>cand;
i need to traverse the strings in depths of recursion and want them unaltered even with re-sizing. how do i do it? the iterators i was using previously get invalidated on re-sizing i want a way around.. here's the previous attempt.
for(itr[d] = cand[d][i][j].begin(); itr[d] !=cand[d][i][j].end(); ++itr[d])
{
//if condition met - proceed to recursive call
//else reset (using ppp and push) and proceed to next element of string
}
Have you tried
func(*(itr[d]));
The dereference operator takes precedence over the indexing operator.
Related
I currently have a problem with vector.erase().
vector<gameObject> gameObjects;
for (auto it = gameObjects.end() - 1; it != gameObjects.begin();)
{
if ((it)->getDestroyed()) {
it = gameObjects.erase(it);
}
else {
--it;
}
}
So gameObject is the base class for everything inside the game and it has a bool flag that basically tells us if the object was destroyed. If the flag is set it should be removed from the vector.
class gameObject
{
protected:
bool toBeDestroyed;
public:
bool getDestroyed();
void markToDestroy();
};
Now the first destroyed object gets removed from the vector successfully and then I get get an error that iterator is not dereferencable, pointing to the vector library at line 73(?).
I then check with the msvc debugger. In the data preview it shows that iterator points to the last/newest element of gameObjects. It is then removed (erase(it)) and AFTERWARDS the data preview doesn't change and calling it->getDestroyed() results in the error message.
Debug assertion failed! vector iterator not dereferencible.
PS: I checked cplusplus.com and vector.erase should return a new, valid iterator so I'm not sure where I'm messing it up.
€: After I was told about the erase-remove idiom I went ahead and ended up with the following, which doesn't compile. Due to my function being a member of gameObject I'm not sure how to successfully call remove_if. Thanks
gameObjects.erase(remove_if(gameObjects.begin(), gameObjects.end(), gameObject::getDestroyed), gameObjects.end());
€2: A lot of you pointed out the first object isn't being checked. I propably should've pointed that out but the first element is ALWAYS the player and shouldn't be removed. Thanks for your comments nevertheless. I'll try with a simple forward loop without getting too fancy ^^.
€3: I tried Jonathan Mees suggested code but I get the exact same error message. I'll try and find out where exactly it happens but I can't just put a breakpoint into the erasing part anymore. Will mess around a bit.
€4: Problem was solved by removing the else {} condition and always decrementing the iterator. Thanks again for all your replies.
Let's say you have 2 objects in your vector and the last one is is marked as destroyed. When you call erase, it will return a new, valid iterator pointing at the element after the erased element. There is no element after the erased element, so the returned iterator is gameObjects.end(). You then continue to the top of the loop and dereference this iterator, which is not valid. You need to decrement your iterator after the erase if you want it pointing at a valid element.
One other note: If you ever wanted your first element removed, it will not be. Your loop exits when the iterator == gameObjects.begin(), so the first element is never checked.
Is there some reason you wanted to do this in reverse? If there is no specific reason, I would recommend you use the method recommended by #Borgleader.
Your loop is a little messed up - you're iterating backwards, ignoring the first element, and testing some elements multiple times. Might I suggest rbegin() as an alternative?
vector::erase returns the:
Iterator following the last removed element. If the iterator pos refers to the last element, the end() iterator is returned.
Meaning that vector::erase will never return vector::begin (unless you removed the only element in the container.) So it will always be dereferenced again after vector::erase is called. It will be dereferenced even if vector::end was returned by the call to vector::erase which is of course illegal.
Instead of this loop, consider using remove_if which is designed for this purpose:
gameObjects.erase(remove_if(begin(gameObjects),
end(gameObjects),
[](const auto& i){ return i.getDestroyed(); }), end(gameObjects));
EDIT:
I noticed you try to use this in your edit. You cannot use a bare function pointer as the predicate. If you want to avoid a lambda, you should consider the use of mem_fn:
gameObjects.erase(remove_if(begin(gameObjects),
end(gameObjects),
mem_fn(&gameObject::getDestroyed)), end(gameObjects));
Live Example
If there's difficulty in reading that line feel free to use as many variable as you like:
auto p = mem_fn(&gameObject::getDestroyed);
auto result = remove_if(begin(gameObjects), end(gameObjects), p);
gameObjects.erase(result, end(gameObjects));
I have been struggling to put a vector object into a project im doing
I have read what little i could find about doing this and decided to give it a go.
std::vector<BrickFalling> fell;
BrickFalling *f1;
I created the vector. This next piece works fine until i get to the erase
section.
if(brickFall == true){
f1 = new BrickFalling;
f1->getBrickXY(brickfallx,brickfally);
fell.push_back(*f1);
brickFall = false;
}
// Now setup an iterator loop through the vector
vector<BrickFalling>::iterator it;
for( it = fell.begin(); it != fell.end(); ++it ) {
// For each BrickFalling, print out their info
it->printBrickFallingInfo(brick,window,deadBrick);
//This is the part im doing wrong /////
if(deadBrick == true)// if dead brick erase
{
BrickFalling[it].erase;//not sure what im supposed to be doing here
deadBrick = false;
}
}
You can totally avoid the issue by using std::remove_if along with vector::erase.
auto it =
std::remove_if(fell.begin(), fell.end(), [&](BrickFalling& b)
{ bool deadBrick = false;
b.printBrickFallingInfo(brick,window,deadBrick);
return deadBrick; });
fell.erase(it, fell.end());
This avoids the hand-writing of the loop.
In general, you should strive to write erasure loops for sequence containers in this fashion. The reason is that it is very easy to get into the "invalid iterator" scenario when writing the loop yourself, i.e. not remembering to reseat your looping iterator each time an erase is done.
The only issue with your code which I do not know about is the printBrickFallingInfo function. If it throws an exception, you may introduce a bug during the erasure process. In that case, you may want to protect the call with a try/catch block to ensure you don't leave the function block too early.
Edit:
As the comment stated, your print... function could be doing too much work just to determine if a brick is falling. If you really are attempting to print stuff and do even more things that may cause some sort of side-effect, another approach similar in nature would be to use std::stable_partition.
With std::stable_partition you can "put on hold" the erasure and just move the elements to be erased at one position in the container (either at the beginning or at the end) all without invalidating those items. That's the main difference -- with std::stable_partition, all you would be doing is move the items to be processed, but the items after movement are still valid. Not so with std::remove and std::remove_if -- moved items are just invalid and any attempt to use those items as if they are still valid is undefined behavior.
auto it =
std::stable_partition(fell.begin(), fell.end(), [&](BrickFalling& b)
{ bool deadBrick = false;
b.printBrickFallingInfo(brick,window,deadBrick);
return deadBrick; });
// if you need to do something with the moved items besides
// erasing them, you can do so. The moved items start from
// fell.begin() up to the iterator it.
//...
//...
// Now we erase the items since we're done with them
fell.erase(fell.begin(), it);
The difference here is that the items we will eventually erase will lie to the left of the partitioning iterator it, so our erase() call will remove the items starting from the beginning. In addition to that, the items are still perfectly valid entries, so you can work with them in any way you wish before you finally erase them.
The other answer detailing the use of remove_if should be used whenever possible. If, however, your situations does not allow you to write your code using remove_if, which can happen in more complicated situations, you can use the following:
You can use vector::erase with an iterator to remove the element at that spot. The iterator used is then invalidated. erase returns a new iterator that points to the next element, so you can use that iterator to continue.
What you end up with is a loop like:
for( it = fell.begin(); it != fell.end(); /* iterator updated in loop */ )
{
if (shouldDelete)
it = fell.erase(it);
else
++it;
}
Does C++ have a pre-built method to identify which element you are on in your foreach loop, or if there is a way to identify if you are on your last element? Or do I have to do it manually with a counter?
No, there is no such built-in way. Nor could there be for iterators in general, because iterators aren't required to know that they are "almost" at the end.
If you find yourself needing the index your probably better off using a regular for loop
If you need the last element, how about using another iterator to store it before you go to the next item in the container? If you set both to the start and then at the end of you loop before you get the next element (increment or decrement the iterator) , set last iterator to current and then get the next.
Something like this:
container current::iterator;
container last::iterator;
current = container.first();
last = current; // or contianer.first();
while ( current is valid )
{
// do something
last = current;
// get the next item
current = container.next(); // or current++;
// depending upon container or
// iterator
}
That way you don't have to rewrite your loop, but you do need to check to make sure your container is not empty before this.
I want to compare the current and next element of a set of addresses . I tried the following code
struct Address{
string state;
string city;
}
if((*it).state == (*(it+1)).state){
}
But the compiler gave an error that no match for operator+ in "it+1". On cplusplus.com I found that + operator is not supported for set containers. So I am unable to figure out a way to access both the current and the next element of a set in the same if statement.
But ++ is provided, so you can write:
?::iterator next = it;
next++;
Just create a copy of the iterator, advance it(++), then compare. Or, if your standard library has it, you can use the c++11 next function from the <iterator> library.
if(it->state == std::next(it)->state)
As you already found out the operator + is not supported for std::set iterators, since those are only bidirectional iterators and not random access iterators. So if you want to access the next element at the same time as the current one you have to make a copy and increment that one:
std::set<Address>::iterator next_it = it;
++next_it;
if(it->state == (next_it)->state)
If you are using c++11 this code can be simplyfied using the std::next function found in <iterator>(which basically does the same thing):
if(it->state == std::next(it)->state)
Of course writing that function is pretty trivial, so you could always write your own next when coding pre C++11 .
Also: Remember to make sure that the next iterator isn't equal to set.end()
I wish to insert into a c++ vector at a known position. I know the c++ library has an insert() function that takes a position and the object to insert but the position type is an iterator. I wish to insert into the vector like I would insert into an array, using a specific index.
This should do what you want.
vector<int>myVec(3);
myVec.insert(myVec.begin() + INTEGER_OFFSET, DATA);
Please be aware that iterators may get invalidated when vector get reallocated. Please see this site.
EDIT: I'm not sure why the other answer disappeared...but another person mentioned something along the lines of:
myVec.insert(INDEX, DATA);
If I remember correctly, this should be just fine.
It's always nice to wrap these things up:
template <typename T>
T& insert_at(T& pContainer, size_t pIndex, const T::value_type& pValue)
{
pContainer.insert(pContainer.begin() + pIndex, pValue);
return pContainer;
}
That should do it. There is a now deleted answer that you can construct an iterator from an index, but I've never see that before. If that's true, that's definitely the way to go; I'm looking for it now.
Look at that debugging trace. The last thing that's executed is std::copy(__first=0x90c6fa8, __last=0x90c63bc, __result=0x90c6878). Looking back at what caused it, you called insert giving the position to insert at as 0x90c63bc. std::copy copies the range [first, last) to result, which must have room for last - first elements. This call has last < first, which is illegal (!), so I'm guessing that the position you're giving to insert at is wrong. Are you sure vnum hasn't underflowed somewhere along the line? In GDB with that trace showing, you should run
frame 10
print vnum
to check. In fact, if you haven't just abbreviated in your question, I've just found your bug. Your second line is:
new_mesh->Face(face_loc)->vertices.insert(vertices.begin()+vnum+1, new_vertices[j]);
It should have been:
new_mesh->Face(face_loc)->vertices.insert(new_mesg->Face(face_loc)->vertices.begin()+vnum+1, new_vertices[j]);
The first line gives the insertion point relative to the start of some other variable called vertices, not the one you want to insert into.