473,769 Members | 2,102 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Why pointer to member function?

Ben
Hi, there.

Recently I was working on a problem where we want to save generic
closures in a data structure (a vector). The closure should work for
any data type and any method with pre-defined signature.

When developing this lib, I figured that the
pointer-to-member-function, although seemingly an attractive solution,
does not work well for us.

The size and the memory model of a generic PTMF is not guaranteed,
therefore, cannot be saved in a heterogeneous container.

My solution turned out to be a C callback function pointer.

That is, instead of using a "int T::(*f)()", use a "int (*f)(T*)".

Although a wrapper function that does the forward call is needed, it
solved our problem.
For instance:

instead of calling

add_closure(&ob j, &MyClass::f) ;

I do
int mywrapper(*MyCl ass pobj){
return pobj->f();
}
add_closure(&ob j, &mywrapper);

Here, 2 assumptions were made:
1. all pointers have the same size as void*
2. all function pointers have the same size.

Then, the annoying wrapper function makes me think:

Why PTMF in the first place?
What if the language generates the wrapper function implicitly and
makes MyClass::f a regular function pointer of type int (*)
(MyClass*)?

At least it can make my life much easier. And I wonder whose life will
it make harder?

Dislike the ptmf(pobj) syntax? Still like the pobj->ptmf()syntax ? No
problem, the language can still do that, as long as it guarantees the
binary memory model of a PTMF is a function pointer. I don't mind
doing a reinterpret_cas t here.

Well, just when I'm about to finish, my gut's feeling starts yelling
hard: "No! It can't be right. This must have been thought over 1000
times! You must be missing something here."

"All right, sir. so what am I missing here?"
Jul 22 '05
37 5019
Ben wrote:
...
If standard does not make a guarantee here, I'll have to assume that
it is NOT safe for a roundtrip between any two PTMs, generally
speaking.


The standard _does_ make a guarantee here. The explicit guarantee is
given, once again, in 5.2.10/9.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #31
Andrey Tarasevich <an************ **@hotmail.com> wrote in message news:<MY******* *************@c omcast.com>...
Ben wrote:
It is safe between any two _PMFs_ (pointer-to-member-function) types. As
it is safe between any two pointer-to-ordinary-function types.

<snip>
My experience with VC is limited to VC6 and I don't know how much it is
different from VC7 in this respect. VC6 happens to support several PMF
models. The default one is called "Best-case always", which means that
VC6 is trying to optimize the size of PMFs by analyzing the class
hierarchy and choosing the size of the PMF accordingly. The logic it
uses is simple: if there's no multiple inheritance in the given class
and any of its ancestors, then the only thing PMFs to member functions
of this class need to store is the function's entry point (4 bytes
long). No additional information is needed. Otherwise (i.e. there's
multiple inheritance somewhere above in the hierarchy) VC6 would use
fully functional PMFs (8 bytes long).

It is easy to demonstrate that this VC6's logic is flawed and will lead
to non-standard conforming behavior in certain contexts (my original
example is one of such contexts, 'reinterpret_ca st' round-trip is
another, just to name a few). However, there are a couple of compiler
options that will force VC6 to always use
multiple-inheritance-compatible PMFs regardless of the inheritance
structure (see '/vmg', '/vmm').

I'm pretty sure (although I could be wrong) that what you observe in
your experiment with VC7 happens for similar reasons. The source and
destination pointer types are so different internally that even
'reinterpret_ca st' refuses to convert one into another. Maybe you should
check the compiler's documentation and see whether if describes some
options similar to '/vm...' in VC6.


I have recently written an article on this topic. There have been many
attempts to 'hack' closure pointers into C++; most fail because of an
inadequate understanding of the implementation of member function
pointers.
My article documents exactly what popular compilers are doing. I also
provide an implementation that satisfies Ben's original goal: closure
pointers without the use of new. I also provide operator == and !=, a
significant limitation of boost::function .

http://www.codeproject.com/cpp/FastDelegate.asp

Unfortunately, for MSVC and Intel C++, it's only possible with a nasty
hack. The portability is quite good: it works on MSVC 6, 7, 7.1, Gnu
3.2, and the latest versions of Intel C++ for Windows, Intel C++ for
Itanium, Digital Mars C++, Metrowerks (x86). It's also been compiled
on Comeau C++. Recently I've also got it working on BCB5.5, but that
version is not yet uploaded to the website.

There are a few errors in the article which I need to correct, but I
think you'll still find it an interesting read. It has *much* more
information than I've seen anywhere else.

Incidentally, if you use the /vmg option on VC6 (without specifying
/vmm or /vms), the compiler generates incorrect code!! In the virtual
inheritance case, it can end up calling the wrong function... Only
happens in fairly obscure circumstances, but it's an appalling bug.
They fixed this for VC7, but I haven't seen it mentioned anywhere.

-Don.
Jul 22 '05 #32
On 15 Jun 2004 00:44:44 -0700, da*****@yahoo.c om.au (Don Clugston)
wrote:
http://www.codeproject.com/cpp/FastDelegate.asp


Interesting article! I haven't actually finished reading it, but found
this sentence:

"You're even allowed to overload the ->* operator, though why you want
to do such a thing is beyond my comprehension."

FWIW, Scott Meyers wrote a good article about overloading ->* in "Dr.
Dobb's Journal" of October 1999. You can find the beginning of it
here:

http://www.ddj.com/documents/s=898/ddj9910b/
--
Bob Hairgrove
No**********@Ho me.com
Jul 22 '05 #33
On 15 Jun 2004 00:44:44 -0700, da*****@yahoo.c om.au (Don Clugston)
wrote:

[snip]

http://www.codeproject.com/cpp/FastDelegate.asp

[snip]

PS - the link to the article by Jan Gray referenced by your article
doesn't seem to work for me.
--
Bob Hairgrove
No**********@Ho me.com
Jul 22 '05 #34
Am Mon, 14 Jun 2004 08:57:36 -0400 schrieb Jeff Flinn <NO****@nowhere .com>:

Thank you for responding. I like your proposal. There are things similar
to what I began. Others are less important. But I also have some questions:

To 3: My serialization can load newer files in older versions. I made bad
experience with serialization that could do only the other way.
I am doing this by saving the size of the object ( I do this for
inheritance levels also, so I can add members to a base class also. If an
inheritance Level is small I can still omit this. ) When deserializing a
newer file, any data after the members known in the old versions are
omitted and the formatter jumps to the point after the current object.
Deserializing an older file, standard values replace any missing data,
when the end of an onject is reached in the stream but still values are
demanded.

The syntax in your terms:

ar & SObject( pmData1, "mData1", pData1default );

I also thought about joining de- and serialization methods. I was just a
matter of blindness :-)

To 4: I don't want to save objects twice, so if I am the owner of an
object I do the above, but when I just point to an object owned by someone
else I do:

ar & SRef( pmData1, "mData1", pData1default );

The base should be done like:

ar & SBase( ... ) <- here I was passing a function pointer, now it is open
what I'll do, I also want to be able to save the base as "inline" and omit
the size of the base and therefore I cannot change the base class'
serialization later. Maybe good for small bases.

Also important for me is references to objects that are not yet serialized
when serializing or not yet deserialized when deserializing. I keep a hash
map of pointers and stream positions to resolve them at the end of the
serialization.

Oh, I jast saw that Point 5 is probably addressing this issue.

To 11:

how is this useful manner of xml serialization. I have two requirements
only: I want to control wether something is a node or an attribute. And I
want to control the name for the attributes and nodes. I cannot see this
in your code examples in your posting, but I assume that I will find it in
the library docs that I am going to read this evening.

template< class Archive > void serialize( Archive& ar, const int
version )
{
ar & mData1;
ar & mData2;

...
}

Prepend the member serialization with:

ar & boost::serializ ation::base_obj ect<base_class_ of_T>(*this);
So, my problem regarding the function pointer is, that the functions are
virtual. They have to be virtual, because if the object is serialized
through a base class (this)pointer, I want the complete object to be
serialized.


boost::serializ ation does not use/require a common base class for
serialization, thereby avoids this problem.


Hmm, there`s something I did not understand. I guess the serialization
method can be virtual. Otherwise I couldn't pass an arbitrary Object, that
I point to via ObjectBase*, to the serializing mechanism. If the method is
virtual, do you make sure, when calling the serialize method, that the
version is called that belongs to the base class and not to the complete
object's class?

It seems this library is cloase to what I have/what I want. If it fits and
works well I will definitely need it. So, thank you for pointing me to it.

cheers

Ingo
--
Erstellt mit M2, Operas revolutionärem E-Mail-Modul:
http://www.opera.com/m2/
~ Samba, more than a low cost File and Printer server ~
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----
Jul 22 '05 #35

"Ingo Nolden" <in**********@S PAMrecurdyn.org > wrote in message
news:op******** ******@news.uni v-angers.fr...
Am Mon, 14 Jun 2004 08:57:36 -0400 schrieb Jeff Flinn <NO****@nowhere .com>:
Thank you for responding. I like your proposal. There are things similar
Woe, It's Robert Ramey's proposal not mine. I just use it( with great
pleasure).
to what I began. Others are less important. But I also have some questions:
To 3: My serialization can load newer files in older versions. I made bad
I've never come across a product that is forward-compatible before, or at
least was visibly so. When you operate on the data loaded with an older
version of the software, and then serialize, don't you lose information?
experience with serialization that could do only the other way.
I am doing this by saving the size of the object ( I do this for
inheritance levels also, so I can add members to a base class also. If an
inheritance Level is small I can still omit this. ) When deserializing a
newer file, any data after the members known in the old versions are
omitted and the formatter jumps to the point after the current object.
You'd have to bring this up with Robert. You can join the boost devel
mailing list - via Yahoo Groups. I suppose you could derive your own archive
class that could accomodate this requirement.
Deserializing an older file, standard values replace any missing data,
when the end of an onject is reached in the stream but still values are
demanded.
This is how boost::serializ ation works but it's explicit with the version
info stored in the file.

The syntax in your terms:

ar & SObject( pmData1, "mData1", pData1default );

I also thought about joining de- and serialization methods. I was just a
matter of blindness :-)

To 4: I don't want to save objects twice, so if I am the owner of an
object I do the above, but when I just point to an object owned by someone
else I do:

ar & SRef( pmData1, "mData1", pData1default );

The base should be done like:

ar & SBase( ... ) <- here I was passing a function pointer, now it is open
what I'll do, I also want to be able to save the base as "inline" and omit
the size of the base and therefore I cannot change the base class'
serialization later. Maybe good for small bases.

Also important for me is references to objects that are not yet serialized
when serializing or not yet deserialized when deserializing. I keep a hash
map of pointers and stream positions to resolve them at the end of the
serialization.

Oh, I jast saw that Point 5 is probably addressing this issue.
I think so.
To 11:

how is this useful manner of xml serialization. I have two requirements
only: I want to control wether something is a node or an attribute. And I
want to control the name for the attributes and nodes. I cannot see this
in your code examples in your posting, but I assume that I will find it in
the library docs that I am going to read this evening.

template< class Archive > void serialize( Archive& ar, const int
version )
{
ar & mData1;
ar & mData2;

...
}

Prepend the member serialization with:

ar & boost::serializ ation::base_obj ect<base_class_ of_T>(*this);
So, my problem regarding the function pointer is, that the functions are virtual. They have to be virtual, because if the object is serialized
through a base class (this)pointer, I want the complete object to be
serialized.
boost::serializ ation does not use/require a common base class for
serialization, thereby avoids this problem.


Hmm, there`s something I did not understand. I guess the serialization
method can be virtual. Otherwise I couldn't pass an arbitrary Object, that


No ClassBeingSeria lized::serializ e is not virtual.
I point to via ObjectBase*, to the serializing mechanism. If the method is
virtual, do you make sure, when calling the serialize method, that the
version is called that belongs to the base class and not to the complete
object's class?
See "Pointers to Objects of derived Classes" under "Special Considerations"
in the documentation. Generally the library handles these issues
automatically. In cases not automaticlaly handled, you register your classes
using:

#include <boost/serialization/export.hpp>
...
BOOST_CLASS_EXP ORT_GUID(derive d_one, "derived_on e")
BOOST_CLASS_EXP ORT_GUID(derive d_two, "derived_tw o")
It seems this library is cloase to what I have/what I want. If it fits and
works well I will definitely need it. So, thank you for pointing me to it.


Your welcome, I hope it helps.

Jeff Flinn
Jul 22 '05 #36
Ben
> I have recently written an article on this topic. There have been many
attempts to 'hack' closure pointers into C++; most fail because of an
inadequate understanding of the implementation of member function
pointers.

-Don.


Don, I did not go through the gory details of the implementation, but
I love this article. Will recommend it to my friends.

I totally agree with you in that 'delegate' is a much more
preferable,type-safer and simpler solution than PTM. And it is more
OO.

One question about Ryazanov's code (that was my another solution tried
before posting here, very appealing indeed.), is it standard C++ to
have PTM as a template parameter? I'm not a language lawyer, but after
searching the internet the only thing found that can be used as
non-type parameter was "integral type". And don't think PTM is
integral type, is it?

Finally, I may not dare to use your code in production. I tend to
avoid all gray areas whenever I can (the standard but non-portable
reinterpret_cas t of PMF is another gray area that I will stay away
from).

My current solution would be: either my plain wrapper function where I
gain efficiency, or boost:function where I pay some runtime overhead
but gain functor support.
Just hope as you said, 'delegate' can be included in the next release
of the language.
Best Regards,
Jul 22 '05 #37
be****@combined .com (Ben) wrote in message news:<24******* *************** ****@posting.go ogle.com>...
I have recently written an article on this topic. There have been many
attempts to 'hack' closure pointers into C++; most fail because of an
inadequate understanding of the implementation of member function
pointers.

-Don.
Don, I did not go through the gory details of the implementation, but
I love this article. Will recommend it to my friends.

I totally agree with you in that 'delegate' is a much more
preferable,type-safer and simpler solution than PTM. And it is more
OO.


I think that PTM is horribly broken. Allowing you to specify an
overridden function from the derived class instead of through the base
class was IMHO a tragic mistake. That tiny bit of functionality came
at an enormous cost.
One question about Ryazanov's code (that was my another solution tried
before posting here, very appealing indeed.), is it standard C++ to
have PTM as a template parameter? I'm not a language lawyer, but after
searching the internet the only thing found that can be used as
non-type parameter was "integral type". And don't think PTM is
integral type, is it?
It is standard, but a bit wierd. PTM is not integral type. Instead,
it's a *name-based* template parameter, quite distinct from normal
parameters and from integral non-type parameters. The syntax is ugly,
so I'm not sure what theyintened it to be used for. Compiler support
for it is patchy, but improving. I would class it as a light gray
area.
Unfortunately, because of its behaviour with inline functions, you
can't use operator == which is a real shame.
Finally, I may not dare to use your code in production. I tend to
avoid all gray areas whenever I can (the standard but non-portable
reinterpret_cas t of PMF is another gray area that I will stay away
from).
The relationship between "standard" and "portable" is interesting...
the surpising thing about my code is that it's the allegedly standard
part that requires a hack; the non-standard part (invoking the
function once it's been cast) is no problem at all.

My current solution would be: either my plain wrapper function where I
gain efficiency, or boost:function where I pay some runtime overhead
but gain functor support.
Just hope as you said, 'delegate' can be included in the next release
of the language.


I'm a little concerned that since they've included boost::function ,
they may think they've answered the need for delegates/closures. But
really, boost::function generates slow, complicated code for such a
simple concept. I find it very disappointing. And the absence of
operator == is a real limitation which convolutes a lot of code.

-Don.
Jul 22 '05 #38

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
7740
by: David Hill | last post by:
Hello - I am using a library that takes a function pointer as an argument. Is the code below not possible? int library_func(void (*func)(int, short, void *)); I am trying to do this... class Test {
5
9376
by: Newsgroup - Ann | last post by:
Gurus, I have the following implementation of a member function: class A { // ... virtual double func(double v); void caller(int i, int j, double (* callee)(double)); void foo() {caller(1, 2, func);
7
3038
by: jon wayne | last post by:
Hi I'm a little confused here about the lifetime of a static pointer to member function, Say, I declare,define & initialize a static ptr to mem function in the header file of a class(the class is a helper Singleton class, and is created & deleted as and when required) - Where does the static pointer point to when every single instance of the class is deleted. I presume it'll be dangling pointer- as the code seg to which it's
6
8829
by: keepyourstupidspam | last post by:
Hi, I want to pass a function pointer that is a class member. This is the fn I want to pass the function pointer into: int Scheduler::Add(const unsigned long timeout, void* pFunction, void* pParam)
7
3813
by: WaterWalk | last post by:
Hello. I thought I understood member function pointers, but in fact I don't. Consider the following example: class Base { public: virtual ~Base() {} }; class Derived : public Base {
5
4663
by: Tim Frink | last post by:
Hi, I'm experimenting with function pointers and found two questions. Let's assume this code: 1 #include <iostream> 2 class A; 3 4 //////////////////////////////////////////// 5 class B
5
3653
by: Immortal Nephi | last post by:
I would like to design an object using class. How can this class contain 10 member functions. Put 10 member functions into member function pointer array. One member function uses switch to call 10 member functions. Can switch be replaced to member function pointer array? Please provide me an example of source code to show smart pointer inside class. Thanks....
4
4402
by: Immortal_Nephi | last post by:
I had a lot of research to see how function pointer works. Sometimes, programmers choose switch keyword and function in each case block can be called. Sometimes, they choose ordinary function pointer array instead of switch. They believe that ordinary function pointer is much faster than switch. Think of one variable called selectFunction. selectFunction variable can be the range of 0 through 1,000 or more. Load selectFunction...
7
3829
by: ghulands | last post by:
I am having trouble implementing some function pointer stuff in c++ An object can register itself for many events void addEventListener(CFObject *target, CFEventHandler callback, uint8_t event); so I declared a function pointer like typedef void (CFObject::*CFEventHandler)(CFEvent *theEvent);
0
9579
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10208
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9857
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8867
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7404
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5294
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5444
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3952
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3558
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.