View Full Version : is such a code construct possible?
WhatMeWorry
2006.08.22, 06:31 PM
This might be completely stupid but please indulge me.
I was looking at my code recently and I suddenly realized that I do this repeatedly. I have some container which I step through each element. I came across the for_each() algorithm and initially was very excited until I realized it calls a function for each element:
UnaryFunction for_each( iterator start, iterator end, UnaryFunction f );
Anyway, could there be a way to implement something like the following where a container and its iterator is defined and a block of code executed for each element of the container. Something like:
for_all( someContainer, iterator i )
{
// block of code using element
// currently pointed to by i
}
Since for_each is already taken, I named it for_all For some reason, I find it very tedious and error prone in having to type the syntax for begin and end iterators for the for() or while() loops.
Skorche
2006.08.22, 07:03 PM
Not in C/C++.
It's provided in a lot of other languages however.
unknown
2006.08.22, 07:05 PM
using #defines..
ia3n_g
2006.08.22, 08:33 PM
You could define it as a macro:
#define for_all( CONTAINER, ITERATOR) for(ITERATOR=CONTAINER.begin();ITERATOR!=CONTAINER .end();++ITERATOR)
I might have the syntax slightly wrong, but that general idea should work. Just be cautioned that you can't do anything that would make the iterator skip over an element, ie, you couldn't say i=container.erase() in your block of code, because the erase call would advance it one element and then the ++ITERATOR would advance it another.
WhatMeWorry
2006.08.23, 11:32 AM
Thanks!
My knowledge of #define extends to something like
#define pi 3.1415
This gives me something to play with. Although aren't macros generally considered
bad or at least dangerous? I'll treat this just as a curiosity.
I don't suppose the C++ standards committee would throw this in just for little
old me :)
ThemsAllTook
2006.08.23, 12:15 PM
Although aren't macros generally considered bad or at least dangerous?
It's subjective, of course, but there's no inherent danger in using them. #define is essentially just a search-and-replace that the preprocessor runs on your code before compilation. It's up to you to form your own judgement as to how "bad" they are, if you feel the need to do that.
TomorrowPlusX
2006.08.23, 04:56 PM
One final note -- if you're querying CONTAINER.end() with each iteration of the loop you're going to have a bit of a hit, over time. Not huge, but it's more efficient to cache the end position.
Also, using a macro for_all is -- I promise you -- going to bite you. You'll use the code happily for months until one day your block does something to break the iterator ( say, erases an element ) and it'll all blow up. Since the for_all is a macro, it will be absurdly hard to track down exactly why.
Well, maybe I can't promise you this'll happen, but it might.
In my code, whenever I'm iterating through a collection, and the operation being performed may change the collection, I operate on a copy of the collection.
std::vector< Entity* > moribund( _entities );
std::vector< Entity * >::iterator it( moribund.begin() ), end( moribund.end() );
for ( ; it != end; ++it ) delete *it;
_entities.clear();
Of course, I'm in the process of migrating to boost::shared_ptr et al right now so some of that will go away.
ia3n_g
2006.08.23, 10:27 PM
One final note -- if you're querying CONTAINER.end() with each iteration of the loop you're going to have a bit of a hit, over time. Not huge, but it's more efficient to cache the end position.
...which is another reason not to use macros, as trying to include the caching of the end iterator would be a real pain with macro syntax.
By the way, in my experience, cached end() positions are invalidated by erasing elements of a vector, so you should update the cache every time you remove an element from the vector or you will get nasty seg faults.
unknown
2006.08.24, 10:11 AM
...which is another reason not to use macros, as trying to include the caching of the end iterator would be a real pain with macro syntax.
not really actually, make use of arbitrary scoping blocks {} and multiline defines \ and its not a problem to make a macro that does this.
WhatMeWorry
2006.08.24, 12:18 PM
Pardon my ignorance, but what is
boost::shared_ptr
Also, I don't believe I've ever seem some of the following syntax:
// declare a vector of size _entities consisting of pointers to Entity Ok, no problem
std::vector< Entity* > moribund( _entities );
// declare an iterator named it for said vector. New Alert! (Guess you can define a
// range here?) Is this how you "cache the end position"?
std::vector< Entity * >::iterator it( moribund.begin() ), end( moribund.end() );
// assume it starts at begining of previously defined range?
for ( ; it != end; ++it ) delete *it;
_entities.clear();
In my code, whenever I'm iterating through a collection, and the operation being performed may change the collection, I operate on a copy of the collection
If the collection size became large enough, wouldn't this technique become prohibatively expensive? And what do you do if you indeed want to change the collection?
Sorry for being all over the place here with questions, but alot of this stuff is new
to me and I love collecting new techniques to improve my coding skills (or lack thereof).
vBulletin® v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.