Quick question about for

Started by
9 comments, last by Fruny 18 years, 11 months ago
I was wondering, if I use a function to retreive a value for the for function, will it be retreieved every loop, or is it just retreived at the beggining?

for(int x; x < Variable.GetValue(); x++)
Basically, I want to go through a vector and do some stuff to its variables, and if it returns 1, the specific element would be deleted. In this scenario, the size of the vector should decrease and the loop should be done one less time. Hence, that's why the retreived value needs to be updated every loop.

//Vector is a vector of pointers
 for(int x = 0; x < Vector.size(); x++)
   if(Vector[x]->Animate(Time)) //if returns 1, delete it
      {
       delete Vector[x];
       Vector.erase(Vector.begin()+x);
      }


I've actually gone and tested it out and it doesn't get me any errors, so I think I'm fine. Thanks!
Comrade, Listen! The Glorious Commonwealth's first Airship has been compromised! Who is the saboteur? Who can be saved? Uncover what the passengers are hiding and write the grisly conclusion of its final hours in an open-ended, player-driven adventure. Dziekujemy! -- Karaski: What Goes Up...
Advertisement
its evaluated every iteration. just fyi:

for( initializations; conditions; loop operation )
{...}

In the 'for' construct, only initialization occurs ONCE. All others occur for each iteration. So watever u put in condition will be evaluated each round irrespective if its a function or variable. Hope that helps.
- To learn, we share... Give some to take some -
I could be wrong, but I'm not sure if that'll erase the whole vector if they all return 1. Problem is that x is increasing while the vector is decreasing:

Vector: { 0, 1, 2, 3, 4, 5 }

X = 0 so we delete Vector[0]

Vector: { 1, 2, 3, 4, 5 }

X = 1 so we delete Vector[1]

Vector: { 1, 3, 4, 5 }

X= 3 so we delete Vector[2]

Vector: { 1, 3, 5 }

X = 4 which is bigger than the Vector's size.

Can you see what I mean?

Things will really get messy anytime there are two deletions needed in a row since the next one will take the previous one's place, while the index will still be incremented.

If I'm making any sense (again, I could be wrong), you should be able to decrement x anytime you delete something and be fine.






-------------------------------See my tutorial site: Click here
You're not wrong, just in case you were curious. It is indeed skipping elements.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
ah, yes, I was afraid of that...

so putting x-- in the delete section should fix the issue, right?
Comrade, Listen! The Glorious Commonwealth's first Airship has been compromised! Who is the saboteur? Who can be saved? Uncover what the passengers are hiding and write the grisly conclusion of its final hours in an open-ended, player-driven adventure. Dziekujemy! -- Karaski: What Goes Up...
Yeah, just make sure you only decrement when you delete and it should work fine.
-------------------------------See my tutorial site: Click here
std::vector<whatever*>::iterator itor = Vector.begin();while(itor != Vector.end()){   if((*itor)->Animate(Time))   {      delete *itor;      itor = Vector.erase(itor);   }   else ++itor;}


Or even

#include <functional>#include <algorithm>struct AnimateAndDeleteIfDead :   std::unary_function<whatever*, bool>{   some_time_type t_;   AnimateAndDeleteIfDead(some_time_type t) : t_(t) {}   bool operator()(whatever* ptr)   {      bool dead = ptr->Animate(t);      if(dead) delete ptr;      return dead;   }};...std::vector<whatever*>::iterator garbage;garbage = std::remove_if( Vector.begin(), Vector.end(),                          AnimateAndDeleteIfDead(Time) );Vector.erase(garbage, Vector.end());
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Or, if you're really into generic code

#include <cstdlib>#include <functional>#include <algorithm>#include <iostream>#include <vector>template<class Itor, class Pred, class Func>Itor remove_if_cleanup( Itor first, Itor last, Pred pred, Func cleanup){   Itor write = first;   while(first != last)   {      if( pred(*first) )      {          cleanup(*first);          *write = *first;          ++write;      }      ++first;   }   return write;}template<class T>struct delete_ptr :   std::unary_function<T*, void>{   void operator()(T* ptr) const { delete ptr; }};struct whatever{   bool Animate(int time) { return time % 2; }   ~whatever() { std::cout << "deleted" << std::endl; }};int main(){   std::vector<whatever*> vec;   for(int i = 0; i < 30; ++i) vec.push_back(new whatever);   int time = 1;   std::vector<whatever*>::iterator garbage;   garbage = remove_if_cleanup( vec.begin(), vec.end(),                                std::bind2nd                                (                                   std::mem_fun(&whatever::Animate),                                   time                                 ),                                delete_ptr<whatever>()                               );   vec.erase( garbage, vec.end() );}


Or you can take a leaf from std::bind2nd and write your own functor combiner

#include <cstdlib>#include <functional>#include <algorithm>#include <iostream>#include <vector>template<class Pred, class Func>struct caller_if :   std::unary_function< typename Pred::argument_type,                        typename Pred::result_type >{   Pred pred_;   Func func_;   caller_if( Pred pred, Func func ) :      pred_(pred),      func_(func)   {}   typename Pred::result_type operator()( typename Pred::argument_type arg )   {      bool test = pred_(arg);      if(test) func_(arg);      return test;   }};template<class Pred, class Func>caller_if<Pred,Func> call_if( Pred pred, Func func ){   return caller_if<Pred,Func>(pred, func);}template<class T>struct delete_ptr :   std::unary_function<T*, void>{   void operator()(T* ptr) const { delete ptr; }};struct whatever{   bool Animate(int time) { return time % 2; }   ~whatever() { std::cout << "deleted" << std::endl; }};int main(){   std::vector<whatever*> vec;   for(int i = 0; i < 30; ++i) vec.push_back(new whatever);   int time = 1;   std::vector<whatever*>::iterator garbage;   garbage = remove_if( vec.begin(), vec.end(),                        call_if                        (                            std::bind2nd                           (                               std::mem_fun(&whatever::Animate),                              time                           ),                           delete_ptr<whatever>()                        )                      );   vec.erase( garbage, vec.end() );}


Or you may pull in the Boost Lambda library

#include <algorithm>#include <iostream>#include <vector>#include <boost/lambda/lambda.hpp>#include <boost/lambda/bind.hpp>#include <boost/lambda/if.hpp>#include <boost/lambda/construct.hpp>using namespace boost::lambda;struct whatever{   bool Animate(int time) { return time % 2; }   ~whatever() { std::cout << "deleted" << std::endl; }};int main(){   std::vector<whatever*> vec;   for(int i = 0; i < 30; ++i) vec.push_back(new whatever);   int time = 1;   bool dead;   std::vector<whatever*>::iterator garbage;   garbage = remove_if( vec.begin(), vec.end(),                        (                           var(dead) = bind( &whatever::Animate, _1, time ),                           if_( dead )                           [                              bind(delete_ptr(),_1)                           ],                           dead                        )                      );   vec.erase( garbage, vec.end() );}


At which point you might decide to just kill me, because if you had just used a container of smart pointers, no manual deletion would have been needed:

  GNU nano 1.3.4                                            File: foo.cc#include <algorithm>#include <iostream>#include <vector>#include <boost/bind.hpp>#include <boost/shared_ptr.hpp>using namespace boost;struct whatever{   bool Animate(int time) { return time % 2; }   ~whatever() { std::cout << "deleted" << std::endl; }};int main(){   typedef shared_ptr<whatever> sp_whatever;   std::vector<sp_whatever> vec;   for(int i = 0; i < 30; ++i) vec.push_back( sp_whatever(new whatever));   int time = 1;   std::vector<sp_whatever>::iterator garbage;   garbage = remove_if( vec.begin(), vec.end(), bind( &whatever::Animate, _1, time ) );   vec.erase( garbage, vec.end() );}


Have fun.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
...ok that was nuts. ;)
Quote:Original post by Krisc
...ok that was nuts. ;)


I second that.
Comrade, Listen! The Glorious Commonwealth's first Airship has been compromised! Who is the saboteur? Who can be saved? Uncover what the passengers are hiding and write the grisly conclusion of its final hours in an open-ended, player-driven adventure. Dziekujemy! -- Karaski: What Goes Up...

This topic is closed to new replies.

Advertisement