Iterating over Vector and Calling Functions

I have a class that has a vector of other class objects as a member. In many functions of this class, I have to perform the same operation for all objects in the vector:

class Small { public: void foo(); void bar(int x); // and many more functions }; class Big { public: void foo() { for (size_t i = 0; i < VectorOfSmalls.size(); i++) VectorOfSmalls[i]->foo(); } void bar(int x) { for (size_t i = 0; i < VectorOfSmalls.size(); i++) VectorOfSmalls[i]->bar(x); } // and many more functions private: vector<Small*> VectorOfSmalls; }; 

I want to simplify the code and find a way not to duplicate another vector in each function.

I considered the possibility of creating a function that receives a pointer to a function and calls the specified function for each member of the vector. But I'm not sure that using function pointers in C ++ is a good idea.

I also thought about functors and functionoids , but that will make me create a class for each function, and that sounds like overkill.

Another possible solution is to create a function that receives a string and calls the command according to the string:

 void Big::call_command(const string & command) { for (size_t i = 0; i < VectorOfSmalls.size(); i++) { if (command == "foo") VectorOfSmalls[i]->foo(); else if (command == "bar") VectorOfSmalls[i]->bar(); } } void Big::foo() { call_command("foo"); } 

But this can work slowly (unnecessary line creation instead of calling the function), and also creates a problem if the functions have a different signature.

So what would you recommend? Should I leave everything the same as now?

EDIT: I can only use STL and not boost (old compilers).

+4
source share
3 answers

Well, you can rewrite for loops to use iterators and more STLs, for example:

 void foo() { std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::foo)); } void bar() { std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::bar)); } 

Other than that, you can use some macros to avoid multiple redialing, but I'm not a big fan of this. Personally, I like several functions on one that accepts the command line. As it gives you more flexibility as to how the decision is made.

If you go with one function that takes a parameter to decide what to do, I would use an enumeration and a switch like this, it would be more efficient than strings and cascading ifs. In addition, in your example, you have an if to decide what to do inside the loop. It is more efficient to check outside the loop and have redundant copies of the loop, since “which command” should be defined only once per call. (NOTE: you can make a command a template parameter if it is known at compile time, which sounds as it is).

 class Big { public: enum Command { DO_FOO, DO_BAR }; void doit(Command cmd) { switch(cmd) { case DO_FOO: std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::foo)); break; case DO_BAR: std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::bar)); break; } }; 

In addition, as you already mentioned, it’s quite simple to replace the & Small :: whatever symbol with that pointer to a member function and just pass it as a parameter. You can even create a template.

 class Big { public: template<void (Small::*fn)()> void doit() { std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(fn)); } }; 

Then you can do:

 Big b; b.doit<&Small::foo>(); b.doit<&Small::bar>(); 

The good thing about this and regular parameter methods is that Big doesn't need to be changed if you change small to have more routines! I think this is the preferred method.

If you want to be able to handle one parameter, you also need to add bind2nd, here is a complete example:

 #include <algorithm> #include <functional> #include <iostream> #include <vector> class Small { public: void foo() { std::cout << "foo" << std::endl; } void bar(int x) { std::cout << "bar" << std::endl; } }; class Big { public: template<void (Small::*fn)()> void doit() { std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(fn)); } template<class T, void (Small::*fn)(T)> void doit(T x) { std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::bind2nd(std::mem_fun(fn), x)); } public: std::vector<Small *> VectorOfSmalls; }; int main() { Big b; b.VectorOfSmalls.push_back(new Small); b.VectorOfSmalls.push_back(new Small); b.doit<&Small::foo>(); b.doit<int, &Small::bar>(5); } 
+16
source

If you are using the std library, you should take a look at for_each .

You note that using function pointers in C ++ may not be a good idea, but for your concern to be fast, you have to make sure that this is even the performance bottleneck you are in before you worry.

+4
source

Try boost :: function and boost :: bind :

 void Big::call_command(const boost::function<void (Small*)>& f) { for (size_t i = 0; i < VectorOfSmalls.size(); i++) { f(VectorOfSmalls[i]); } } int main() { Big b; b.call_command(boost::bind(&Small::foo, _1)); b.call_command(boost::bind(&Small::bar, _1, 5)); } 
0
source

All Articles