• ### Announcements

#### Archived

This topic is now archived and is closed to further replies.

# std: want to use for_each !..

## Recommended Posts

Hi! I''m looking at my code and thinking, "what the?.. this would be so much clearer with for_each()!"

ORC::ParticleFX::Container::const_iterator
i = particleFX.GetSystems().begin();
for(; i != particleFX.GetSystems().end(); ++i)

but... neither mem_fun nor ptr_fun feels like the thing I need? "No lies of sugar can sweeten the sournes of reality" }+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

##### Share on other sites
mem_fun and ptr_fun are often the wrong way to go about using algorithms such as for_each. What you really should do is write a functor. A functor is a class whose instances can behave like functions; that is, they overload the parenthesis operator. Read the STL docs for more info.

How appropriate. You fight like a cow.

##### Share on other sites
This is a rough one:

  #include <string> #include <vector> #include <algorithm> #include <functional> using namespace std;#include <boost\compose.hpp> using namespace boost;   vector<Particle*> particles;CListBox lbSystem; for_each	(	particles.begin(),	particles.end(),	compose_f_gx(		bind1st(			mem_fun(CListBox::AddString),			&lbSystem			),		compose_f_gx(			mem_fun_ref(std::string::c_str),			mem_fun(Particle::GetName)			)		)	);

You can see why writing a functor is often easier.

##### Share on other sites

    struct addStringToListBox {    addStringToListBox(CListBox& list)//create object that remembers the listbox        : list_(list) {}    void operator()(const Particle* particle) {// function call to add name to listbox        list_.AddString(particle->GetName().c_str());    }private:    CListBox& list_;};vector<Particle*> particles;CListBox lbSystem;// the function object is created with the listbox as a parameter// and gets passed to the for_each function.// for_each calls operator()(Particle*) on the function object for every Particle* in the vector.std::for_each(particles.begin(), particles.end(), addStringToListBox(lbSystem));

If there were other things that needed adding to the listbox other than particles you could add more: operator()(Model*), operator()(Label*) etc.

[edited by - petewood on May 28, 2003 5:02:24 AM]

##### Share on other sites
cool

I know how to make functors, I especially love my SafeDelete

I was just hoping that I didn't need to write a functor for adding strings to a list... Am I wrong to make this conclusion: making a functor for this purpose won't increase the efficiency nor the readability of my code?

Because if it doesn't, it isn't worth it

(oh for you curios people out there, having a functor SafeDelete is great! I use it everytime I want to delete a pointer, if it's "alone" or in a container!

        struct SafeDelete{  template <typename T>  inline void operator () ( T*& ptr ) const  {      delete ptr;      ptr = 0;  }};

any comments on my SafeDelete? hmm come to think of it, I think I based it on one I saw in Effective STL by Scott Meyers)

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

[edited by - Seriema on May 29, 2003 7:30:23 AM]

[edited by - Seriema on May 29, 2003 7:35:49 AM]

[edited by - Seriema on May 29, 2003 7:44:25 AM]

##### Share on other sites
http://boost.org/libs/lambda/doc/index.html

##### Share on other sites
I have a few comments on SafeDelete... calling delete on 0 is safe, so you don''t need to check for nullity before you delete. Also, the pointer you set to 0 is a local pointer for that function, which has no effect whatsoever on the pointer you pass to SafeDelete.

##### Share on other sites
quote:
I was just hoping that I didn't need to write a functor for adding strings to a list... Am I wrong to make this conclusion: making a functor for this purpose won't increase the efficiency nor the readability of my code?

Well, you don't have to write one - I've written one for you.

I think it is far more readable than writing an explicit loop as in your first example and MKH's solution is only easy to understand if you know what's going on already! Efficiency - all three solutions will evaluate to pretty much the same thing.

Your safe delete isn't any safer by having the check for a null pointer. delete checks that anyway so you are introducing an inefficent extra check. The reason it is safe is because it remembers to set the pointer to zero afterward. Also you don't need the inline as template header functions are inline anyway.

      struct SafeDelete{  template <typename T>  void operator () ( T*& ptr ) const  {    delete ptr;    ptr = 0;  }};

edit: changed to pass by reference (thanks dalleboy)

[edited by - petewood on May 29, 2003 8:48:12 AM]

##### Share on other sites
guess my edit''s didn''t come in time, unless it was you that posted torbjörn?

chatted with a friend on MSN about SafeDelete right after I posted and changed it a bit.

macros... na... they''re generally not wanted and ain''t usefull for std::algorithms

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

##### Share on other sites
petewood: I was under the impression that templates only inline under the same conditions as normal inlines, no loops etc? as always, inlines are only a recommendation to the compiler. It''ll probably inline it anyway (since it''s just two rows), but I put it there more for the coder than the compiler.

I appreciated that you wrote the functor for me. If you guys think it''s more readable I''ll use it. It can be usefull for other cases later on maybe?

thinking of going up the hiearchy a little though, as high as where the function AddString() is introduced in MFC. gonna check on that..

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

##### Share on other sites
quote:
Original post by petewood
The reason it is safe is because it remembers to set the pointer to zero afterward.

But only the local copy of the pointer, it will not affect the calling object, unless you change it so it takes a reference to a pointer.

[How To Ask Questions|STL Programmer''s Guide|Bjarne FAQ|C++ FAQ Lite|C++ Reference|MSDN]

##### Share on other sites
quote:
daleboy: But only the local copy of the pointer, it will not affect the calling object, unless you change it so it takes a reference to a pointer.

right you are

[edited by - petewood on May 29, 2003 8:47:21 AM]

##### Share on other sites
dalleboy: but I did change mine earlier today, it takes a pointer reference

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

##### Share on other sites
OP said:
  ORC::ParticleFX::Container::const_iterator     i = particleFX.GetSystems().begin();  for(; i != particleFX.GetSystems().end(); ++i)    lbSystems.AddString( (*i)->GetName().c_str() );

why not...

  ORC::ParticleFX::Container::const_iterator it;for(it=particleFX.GetSystems().begin;    it != particleFX.GetSystems().end();    lbSystems.AddString( (*i)->GetName().c_str()), ++it)){}
or some other idiom.

##### Share on other sites
what purpose would that serve?

it's possible but... why? it wasn't clearer, and there are no effeciency benefits? *not to rant or anything*

oh by the way, always try to initialize objects instead of first creating them and after assigning a value.

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

[edited by - Seriema on May 29, 2003 9:35:33 AM]

##### Share on other sites
I wouldn't use a custom functor or any of those compose/bind functors for this task. Custom functors only make the code more scattered and compose/bind make it harder to understand. There's nothing wrong with the for loop in the original post. for_each isn't really much of an abstraction, that it should be blindly pursued.

If you can't do with few standard functors and the loop code can't be abstracted so that it's useful elsewhere, use a plain old for loop. That's my rule of thumb.

[edited by - civguy on May 29, 2003 11:52:13 AM]

##### Share on other sites
The SafeDelete functor is actually quite useful ( I always named mine "deleter" ), especially if you have tons of containers of pointers all over the place.

Although, it''s kind not necessary if you just put containers of boost::shared_ptr''s instead.

##### Share on other sites
Ok, I haven't read the whole thread so this could be way
wrong or stated eariler, but here goes.

What you want is BEER!
What you need is BEER!
and no im not drunk...

BEER in this case is "Better Efficency and Encapsulation Repository"
a utility header coded by yours truly to collect usefull
snippets and neat techniques and soon it will be availbile

Anyways the parts you wan't are

  template <typename R, typename C, typename A>class obj_fun_t{typedef R (C::*fun_t)(A);C *m_pObj;fun_t m_pFun;public:	typedef R return_type;	typedef A argument_type;		obj_fun_t(C* pC, fun_t pFun): m_pObj( pC), m_pFun( pFun){}	R operator()(A arg){ return (m_pObj->*m_pFun)( arg);}};template <typename R, typename C, typename A>obj_fun_t<R, C, A> obj_fun(C *pC, R (C::*pFun)(A)){ return obj_fun_t<R, C, A>( pC, pFun);}template <typename F1, typename F2>class xform_t{	F1 m_xlate;	F2 m_work;public:	xform_t(F1 xlate, F2 work): m_xlate( xlate), m_work( work){}	typename F2::return_type operator()(typename F1::argument_type a){ return m_work( m_xlate( a));}};template <typename F1, typename F2>xform_t<F1, F2> xform( F1 xlate, F2 work){ return xform_t<F1, F2>( xlate, work);}

you know the deal with mem_fun
it transforms from f( obj); to obj->some_func();
what you want here is the bit more involved
f( obj) to class_instance->some_function( obj);

obj_fun solves that =) (there's also a specialication for const member functions but im trying to be terse here)

also since you need to translate the argument you can use xform.

ill show you some code:

  struct B{int f(int i){ cout << i << "\t";}};int mul2(int i){ return i + i;}int main(int argc, char *argv[]){	 	vector<int> ivec;	for(int i = 0; i < 10; ++i)		ivec.push_back( i);	B b;	for_each( ivec.begin(), ivec.end(), xform( ptr_fun(mul2), obj_fun( &b, &B::f)));	cout << endl;		system("PAUSE");	return 0;}

and mul2 would become something along the lines of
inline const char *WhatsYourName( ParticleFX* thing)
{
return thing->GetName().c_str();
}

hope that helps =)
you got my ICQ if you need anyhelp.

[edited by - DigitalDelusion on May 29, 2003 5:26:01 PM]

##### Share on other sites
I guess when I design a system where I am using STL I normally write functions that are consistent so I can use a templated functor. When I need to do searches for objects, I make sure the objects have an ID or GetID() function so that I can use my ''find_if'' templated functor. Same as the safe delete. Likewise, when working with a widget that needs to have data added, I''ll make sure all my widgets have an ''AddString()'' or ''SetWindowText()'' function so I can write a templated AddString functor. Just a thought to avoid all the headache.

##### Share on other sites
well, from the looks of it he''s trying to shoehorn something quite sane into an MFC app... and sanity an M\$ stuff never gets along

##### Share on other sites
quote:
Original post by Seriema
petewood: I was under the impression that templates only inline under the same conditions as normal inlines, no loops etc? as always, inlines are only a recommendation to the compiler. It''ll probably inline it anyway (since it''s just two rows), but I put it there more for the coder than the compiler.

Unfortunetly, there are two concepts called ''inline''. The C++ keyword has little to do with what you are talking about. When you declare a function inline, you are telling the compiler that this function is being declared in a header, and not to produce duplicates of it when compiling so the linker does not get confused.

void test()
{
//...
}

//source1.cpp

//source2.cpp

When it links, you''ll get an error about two functions both called test.

inline void test() fixes the problem.

__inline, __forceinline et. al. will give the compiler hints to inline the code (and are not part of the standard).

##### Share on other sites
when it''s a class member though inline doesn''t matter, does it?

##### Share on other sites
quote:
Original post by petewood
when it's a class member though inline doesn't matter, does it?

I guess you mean this:
class A{public  void f(){ /* do stuff */} // implicit inline};

and that gives you inlining it has the same effect as:

class B{public:  inline void g();// explicit inline};inline void B::g(){ /* do other stuff */

[edited by - DigitalDelusion on May 30, 2003 4:36:12 AM]

##### Share on other sites
Hmm...
void operator () ( T*& ptr ) const

Isn''t a pointer always passed by reference? Enlighten me, please

##### Share on other sites
This would help in the following way:

char* data = new char[1024];delete[] data;// .. lots of code so that we forgot our deletionfor(int i=0; i < 1024; i++) data[i] = 0; //uhoh, data pointed at deallocated memory

The people writing the safe_delete function want it to delete the memory and change the pointer's value to zero . That way they don't have to worry about setting it to zero manually.

So if we want to modify the address stored in the pointer we must pass it by reference. Without it, setting the argument to zero would affect only the function's pointer, not the caller's.

[edited by - antareus on May 30, 2003 5:22:07 PM]

• ### Forum Statistics

• Total Topics
627741
• Total Posts
2978887

• 10
• 10
• 21
• 14
• 14