Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Pointers to member functions are NOT useless

Reply
Thread Tools

Pointers to member functions are NOT useless

 
 
Francesco S. Carta
Guest
Posts: n/a
 
      07-24-2010
Hi there,
after reading an article complaining that pointers to member functions
are misconceived in C++, and after reading a comment about them saying
that they happen to be a rarely necessary feature - if ever necessary at
all - I decided to investigate them to see how I could take advantage of
them, and I also decided to post this message to get the group's feedback.

A pointer to member function is a pointer that can memorize the
displacement of any member function so that we can call that function on
an appropriate object without having to know which function we are
calling in particular - though, the object and the member function must
belong to the same class (please forgive me if this description is
oversimplified, but also please correct me if it happens to be wrong).

I've come to think that this feature can be really useful if we have
objects that can perform different actions in case they are used in a
context or another.

The approach to take (having not pointers to member functions at our
disposal) would be to use a switch or some ifs any time we have to
perform the action, so that we can choose the right function for the
current context or input.

If we happen to have several operations to perform, but the context /
input rarely changes, having to decide which action to perform at each
call is a waste of cycles.

With pointers to member functions we can store our decision about which
member function to call and speed up the whole process.

Since I'm biased towards interfaces and games, the example I post here
below is just a stub of a game where we have a common interface for
several different moving objects - I think the approach I've taken in
that example could lead to a nice infrastructure where different objects
must interact (or refuse to interact) with different environments.

I'd like to ask you if you can come up with some real life examples
where you have taken advantage of pointers to member functions -
unfortunately, being an hobbyist, my best example comes straight from
the top of my head

Thanks for your attention,
cheers,
Francesco

//-------
#include <iostream>
#include <string>

struct ThreeD {
int x;
int z;
int y;
ThreeD(int x = 0, int z = 0, int y = 0) : x(x), z(z), y(y) {}
};

typedef ThreeD Position;
typedef ThreeD Movement;

struct Crash {
Crash(std::string message = "") : message(message) {};
std::string what() const {
return message;
}
std::string message;
};

enum Field {
ground,
water,
air
};

class MovingObject {
public:
MovingObject(Position pos = Position()) : pos(pos) {}
virtual void enter(Field) {}
virtual void move(Movement) {}
protected:
Position pos;
};

class Car : public MovingObject {
public:
Car(Position pos = Position()) : MovingObject(pos), action(0) {}
void enter(Field f) {
switch (f) {
case water:
action = &Car::sink;
break;
case ground:
action = &Car::run;
break;
case air:
action = &Car::fall;
break;
}
}
void move(Movement m) {
if (action) {
(this->*action)(m);
}
}
private:
void run(Movement m) {
pos.x += m.x;
pos.z += m.z;
}
void sink(Movement) {
pos.x -= 1;
}
void fall(Movement) {
pos.x -= 10;
}
void (Car::*action)(Movement);
};

class Airplane : public MovingObject {
public:
Airplane(Position pos = Position())
: MovingObject(pos), action(0) {}
void enter(Field f) {
switch (f) {
case water:
throw Crash("This airplane cannot fly into water");
case ground:
throw Crash("This airplane cannot fly into ground");
case air:
action = &Airplane::fly;
}
}
void move(Movement m) {
if (action) {
(this->*action)(m);
}
}
private:
void fly(Movement m) {
pos.x += m.x;
pos.y += m.y;
pos.z += m.z;
}
void (Airplane::*action)(Movement);
};

class Boat : public MovingObject {
public:
Boat(Position pos = Position()) : MovingObject(pos), action(0) {}
void enter(Field f) {
switch (f) {
case water:
action = &Boat::navigate;
break;
case ground:
throw Crash("This boat cannot navigate onto the ground");
break;
case air:
action = &Boat::fall;
break;
}
}
void move(Movement m) {
if (action) {
(this->*action)(m);
}
}
private:
void navigate(Movement m) {
pos.x += m.x;
pos.z += m.z;
}
void fall(Movement) {
pos.x -= 10;
}
void (Boat::*action)(Movement);
};

class Submarine : public MovingObject {
public:
Submarine(Position pos = Position())
: MovingObject(pos), action(0) {}
void enter(Field f) {
switch (f) {
case water:
action = &Submarine::navigate;
break;
case ground:
throw Crash("Submarines cannot navigate into the ground");
break;
case air:
action = &Submarine::fall;
break;
}
}
void move(Movement m) {
if (action) {
(this->*action)(m);
}
}
private:
void navigate(Movement m) {
pos.x += m.x;
pos.y += m.y;
pos.z += m.z;
}
void fall(Movement) {
pos.x -= 10;
}
void (Submarine::*action)(Movement);
};


int main() {

MovingObject* car = new Car;
car->enter(ground);
car->move(Movement(5));

MovingObject* airplane = new Airplane;
airplane->enter(air);
airplane->move(Movement(10,0,3));

MovingObject* boat = new Boat;
boat->enter(water);
boat->move(Movement(2,2));

MovingObject* submarine = new Submarine;
submarine->enter(water);
submarine->move(Movement(0,0,-3));

try {
submarine->enter(ground);
} catch (Crash c) {
std::cout << c.what() << std::endl;
}
return 0;
}
//-------


--
FSC - http://userscripts.org/scripts/show/59948
http://fscode.altervista.org - http://sardinias.com
 
Reply With Quote
 
 
 
 
Öö Tiib
Guest
Posts: n/a
 
      07-24-2010
On 24 juuli, 18:10, "Francesco S. Carta" <(E-Mail Removed)> wrote:
> I'd like to ask you if you can come up with some real life examples
> where you have taken advantage of pointers to member functions -
> unfortunately, being an hobbyist, my best example comes straight from
> the top of my head


For loosely coupling something.

For example typical silly observer pattern implementation expects my
observer to have virtual handleEvent(Observed& ref) method. Virtual
from IObserver base interface. Why? Looks like direct translation from
java with no brain applied. I can just boost:bind any member function
as an observer functor. Only limit is that it has to have unique
member function name in class (may not have overloads).

That way i need no useless interface base classes and virtuals and lot
of other bloat and nuisance usually connected to loose coupling
patterns. Patterns look like too tightly coupled after such thing
applied for my taste. The calling and binding of member function
pointers should be templatized to not confuse novices. Also i usually
suggest to consider boost::signals2 first when someone needs
multithreaded version of such.
 
Reply With Quote
 
 
 
 
Jonathan Lee
Guest
Posts: n/a
 
      07-24-2010
On Jul 24, 11:10*am, "Francesco S. Carta" <(E-Mail Removed)> wrote:
> Hi there,
> after reading an article complaining that pointers to member functions
> are misconceived in C++, and after reading a comment about them saying
> that they happen to be a rarely necessary feature - if ever necessary at
> all - I decided to investigate them to see how I could take advantage of
> them, and I also decided to post this message to get the group's feedback..


Not to be a Negative Nancy, but I tend to agree with the position that
pointer to member functions are (nearly) useless. I've never used
them.

The problem is there seem to be more suitable idioms in most cases.
Take your example. I'd rather use polymorphism and write something
like

void enter(Field f) { current_field = f; }

void move(Movement m) {
switch(current_field) {
case water: return moveWater(m);
case air: return moveAir(m);
case ground: return moveGround(m);
default: throw std::runtime_error("WTField");
}
}

and let the derived classes implement moveXXX(). And
it's not like it's just the example you came up with
that this could be done with. I think you could
refactor this whole category of uses.

Though I'd still be interested to see what people
can come up with.

--Jonathan

 
Reply With Quote
 
werasm
Guest
Posts: n/a
 
      07-24-2010
On Jul 24, 5:42*pm, Jonathan Lee <(E-Mail Removed)> wrote:

> Not to be a Negative Nancy, but I tend to agree with the position that
> pointer to member functions are (nearly) useless. I've never used
> them.


Strange, I use them all the time. I often use them when
needing to call predicates when using the find_if algorithm
in conjunction with boost::bind. But I also use them to execute
callback in other threads - go figure (variant of the command
pattern).

Kind regards,

Werner

 
Reply With Quote
 
Jonathan Lee
Guest
Posts: n/a
 
      07-24-2010
On Jul 24, 12:08*pm, werasm <(E-Mail Removed)> wrote:
> On Jul 24, 5:42*pm, Jonathan Lee <(E-Mail Removed)> wrote:
>
> > Not to be a Negative Nancy, but I tend to agree with the position that
> > pointer to member functions are (nearly) useless. I've never used
> > them.

>
> But I also use them to execute callback in other threads - go
> figure (variant of the command pattern).


That actually sounds like a good idea. I have some multithreaded
code that I always thought could be cleaner...

--Jonathan
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      07-24-2010
On 07/25/10 04:08 AM, werasm wrote:
> On Jul 24, 5:42 pm, Jonathan Lee<(E-Mail Removed)> wrote:
>
>> Not to be a Negative Nancy, but I tend to agree with the position that
>> pointer to member functions are (nearly) useless. I've never used
>> them.

>
> Strange, I use them all the time. I often use them when
> needing to call predicates when using the find_if algorithm
> in conjunction with boost::bind.


That would be another valid use case, but I haven't used it.

> But I also use them to execute
> callback in other threads - go figure (variant of the command
> pattern).


That's the "exotic RPC" use I alluded to in my earlier post.

--
Ian Collins
 
Reply With Quote
 
Francesco S. Carta
Guest
Posts: n/a
 
      07-24-2010
Jonathan Lee <(E-Mail Removed)>, on 24/07/2010 08:42:08, wrote:

> On Jul 24, 11:10 am, "Francesco S. Carta"<(E-Mail Removed)> wrote:
>> Hi there,
>> after reading an article complaining that pointers to member functions
>> are misconceived in C++, and after reading a comment about them saying
>> that they happen to be a rarely necessary feature - if ever necessary at
>> all - I decided to investigate them to see how I could take advantage of
>> them, and I also decided to post this message to get the group's feedback.

>
> Not to be a Negative Nancy, but I tend to agree with the position that
> pointer to member functions are (nearly) useless. I've never used
> them.


I'm glad you've been able to find other uses for them, reading the
follow-ups of this thread.

I've never used them either, only today I seriously put myself up for
reasoning on it and I found some usage that I considered useful...

> The problem is there seem to be more suitable idioms in most cases.
> Take your example. I'd rather use polymorphism and write something
> like
>
> void enter(Field f) { current_field = f; }
>
> void move(Movement m) {
> switch(current_field) {
> case water: return moveWater(m);
> case air: return moveAir(m);
> case ground: return moveGround(m);
> default: throw std::runtime_error("WTField");
> }
> }
>
> and let the derived classes implement moveXXX(). And
> it's not like it's just the example you came up with
> that this could be done with. I think you could
> refactor this whole category of uses.


....useful in particular to avoid the kind of code you just posted - as I
previously said, in the OP.

You just moved the decision about which function to call from the rarely
used function (the one that sets the context) to the often used function
(the one that should just "do it").

You wasted cycles, and potentially, you heavily slowed down the program:
imagine if there are hundreds or thousands of such objects in a
simulation, would you then try to save as much as possible? I know I would.

--
FSC - http://userscripts.org/scripts/show/59948
http://fscode.altervista.org - http://sardinias.com
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      07-25-2010
On 07/25/10 11:57 AM, Francesco S. Carta wrote:
> Jonathan Lee <(E-Mail Removed)>, on 24/07/2010 08:42:08, wrote:
>
>> The problem is there seem to be more suitable idioms in most cases.
>> Take your example. I'd rather use polymorphism and write something
>> like
>>
>> void enter(Field f) { current_field = f; }
>>
>> void move(Movement m) {
>> switch(current_field) {
>> case water: return moveWater(m);
>> case air: return moveAir(m);
>> case ground: return moveGround(m);
>> default: throw std::runtime_error("WTField");
>> }
>> }
>>
>> and let the derived classes implement moveXXX(). And
>> it's not like it's just the example you came up with
>> that this could be done with. I think you could
>> refactor this whole category of uses.

>
> ....useful in particular to avoid the kind of code you just posted - as
> I previously said, in the OP.
>
> You just moved the decision about which function to call from the rarely
> used function (the one that sets the context) to the often used function
> (the one that should just "do it").
>
> You wasted cycles, and potentially, you heavily slowed down the program:
> imagine if there are hundreds or thousands of such objects in a
> simulation, would you then try to save as much as possible? I know I would.


There's probably a template solution as well if opening up the code to
optimisation is important. That's the thing about C++, there are
invariably many ways to skin a particular cat. Of all the possible
options, function pointers are the least friendly to the optimiser.

Function pointers are more commonly used in C and C++ mainly because C
only has a single skinning technique.

--
Ian Collins
 
Reply With Quote
 
Francesco S. Carta
Guest
Posts: n/a
 
      07-25-2010
Ian Collins <(E-Mail Removed)>, on 25/07/2010 12:18:04, wrote:

> On 07/25/10 11:57 AM, Francesco S. Carta wrote:
>> Jonathan Lee <(E-Mail Removed)>, on 24/07/2010 08:42:08, wrote:
>>
>>> The problem is there seem to be more suitable idioms in most cases.
>>> Take your example. I'd rather use polymorphism and write something
>>> like
>>>
>>> void enter(Field f) { current_field = f; }
>>>
>>> void move(Movement m) {
>>> switch(current_field) {
>>> case water: return moveWater(m);
>>> case air: return moveAir(m);
>>> case ground: return moveGround(m);
>>> default: throw std::runtime_error("WTField");
>>> }
>>> }
>>>
>>> and let the derived classes implement moveXXX(). And
>>> it's not like it's just the example you came up with
>>> that this could be done with. I think you could
>>> refactor this whole category of uses.

>>
>> ....useful in particular to avoid the kind of code you just posted - as
>> I previously said, in the OP.
>>
>> You just moved the decision about which function to call from the rarely
>> used function (the one that sets the context) to the often used function
>> (the one that should just "do it").
>>
>> You wasted cycles, and potentially, you heavily slowed down the program:
>> imagine if there are hundreds or thousands of such objects in a
>> simulation, would you then try to save as much as possible? I know I
>> would.

>
> There's probably a template solution as well if opening up the code to
> optimisation is important. That's the thing about C++, there are
> invariably many ways to skin a particular cat. Of all the possible
> options, function pointers are the least friendly to the optimiser.


That's sure, putting the optimiser in condition to squeeze out the most
is an important thing for me, and I didn't consider the last point you
mention above - I simply wasn't aware of it.

I'm really interested in this subject, because I have implemented
heavily populated simulations in the past and I'm willing to deepen my
grasp on the subject, so any further information about how to replace
pointers to member functions in cases like this would be really welcome.

--
FSC - http://userscripts.org/scripts/show/59948
http://fscode.altervista.org - http://sardinias.com
 
Reply With Quote
 
Jonathan Lee
Guest
Posts: n/a
 
      07-25-2010
On Jul 24, 7:57*pm, "Francesco S. Carta" <(E-Mail Removed)> wrote:
> You wasted cycles, and potentially, you heavily slowed down the program:
> imagine if there are hundreds or thousands of such objects in a
> simulation, would you then try to save as much as possible? I know I would.


This is conjecture, of course. Nor is your assessment about the
performance obvious. In my code, the switch could easily be replaced
with a jump table, which might not be any slower. Also, the use of
a pointer to member function removes the possibility of profile
guided optimization and will probably ruin cache prediction.

Testing, of course, would be necessary. But this example has gone from
"generally useful" to "niche optimization" :/

--Jonathan
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
static member functions vs. member function pointers paul C++ 8 04-30-2009 11:03 AM
overloading non-template member functions with template member functions Hicham Mouline C++ 1 04-24-2009 07:47 AM
overloading non-template member functions with template member functions Hicham Mouline C++ 0 04-23-2009 11:42 AM
Member function pointers to member functions with default arguments Hamish C++ 3 01-25-2008 06:46 AM
Useless thread about some useless statistics Daniel Nogradi Python 0 11-15-2006 11:33 PM



Advertisments