Re: C++ Draw Callback?

New Message Reply Date view Thread view Subject view Author view

Christopher R Volpe (volpe++at++ash.crd.ge.com)
Mon, 09 Dec 1996 09:48:05 -0500


Hansong Zhang wrote:
>
> Chris Volpe wrote:
> >
> > Hansong Zhang wrote:
> > >
> > >
> > > The same thing can be done to non-static member functions, also.
> > > But you need a explicit type conversion:
> > >
> > > chan->setTravFunc( PFTRAV_DRAW, (pfChanFuncType)MyClass::DrawChannel );
> > >
> > > You'll still get an warning about this conversion, but you could
> > > ignore that...
> >
> > No you can't. Non-static member functions have a "this" pointer passed
> > in behind the scenes as part of the calling convention. If you try to
> > invoke the member function as if it were an ordinary function, it will
> > crash immediately if you're lucky, and deceptively appear to work, for
> > now, if you're unlucky. What will likely happen is that your member
> > function will think that the pfChannel* parameter passed in by performer
> > is actually the this-pointer, and will think that the void* parameter
> > passed in is atually the pfChannel* parameter, leaving the void*
> > parameter undefined within the member function, and it all goes downhill
> > from there...
> >
> Good point. I examined my code and realized why the hack worked for
> me. But, a forced type conversion CAN work properly, and it's needed
> when a callback function *cannot* be static for some reason.

Well, this just goes to show that you can lead a person to knowledge,
but you cannot make him think. This forced type conversion CAN work
properly, if you're very unlucky, but it cannot be GUARANTEED to work
properly. And this kind of broken coding is never needed. The only time
a function cannot be a static member function is when it needs to access
non-static members, and in order to do this you need a this-pointer to
indicate whose non-static members you want to access.

> Here's a report
> of what I got, for anybody interested...
>
> I have a global function table of member functions,
>
> functype FuncTable[64] = {
> ...
> (functype)MyClass::draw_for_a_specific_attribute_binding;
> ...
> }

I presume "functype" is NOT a pointer-to-member-function type, but is
rather of type pointer-to-ordinary-function, or equivalently,
pointer-to-static-member-function.

>
> And in another member function of the same class, I select a function from
> the function table and call it:
>
> MyClass::Draw(...) {
> ...
> FuncTable[Index](); // note: this function has no argument
> }

This is a catastrophe waiting to happen.

>
> When MyClass::Draw() is called, the calling stack is like:
>
> stack ptr + 0 | THIS pointer |
> stack ptr + 4 | int index |
> ....

This is what I was referring to earlier when I said "if you're unlucky,
it will appear to work, for now".

>
> And after entering function FuncTable[Index](), THE STACK REMAINS THE SAME
> and the this pointer is still on top of stack, which is happily used by
> draw_for_a_specific.. function!

Today, not necessarily tomorrow.

>
> So for it to work two conditions must be satisfied:
> a) the compiler doesn't put any other implicit parameter in calling stack
> frame (e.g. the return address as they normally have in the stack on PCs).
> b) The called function (i.e. functions suffering from the forced type
> conversion) should have any arguments.
>
> Now, the *correct* way to do it is to pass the "this" pointer explicitly.

No, the *correct* way to do it is *not* to invoke functions via function
pointers that do not have the same type as the function they point to.
Specifically, in your case, the *correct* way to do this is to store,
ahead of time, the pointer to the instance you know you want the
callback function to operate on, in a static class member variable. (And
I presume you already know which instance you want to operate on because
you already suggested passing it explicitly.) And then, your
static-member-function callback should examine this static instance
pointer, and invoke the desired non-static-member-function on *it*.

> i.e. for a variable FuncPtr defined and init'd as:
>
> functype FuncPtr = (functype) MyClass::memberFunc;
>
> we should call it as: FuncPtr(objectPtr, other_arguments);
> - sure we are assuming the compiler places the "this" pointer as the 1st arg,
> which is true for the AT&T cfront and sgi's integrated CC.

But not necessarily true in the next release of these compilers.

-Chris

        "A little knowledge is a dangerous thing"

--

Chris Volpe Phone: (518) 387-7766 GE Corporate R&D Fax: (518) 387-6560 PO Box 8 Email: volpecr++at++crd.ge.com Schenectady, NY 12301 Web: http://www.crd.ge.com/~volpecr ======================================================================= List Archives, FAQ, FTP: http://www.sgi.com/Technology/Performer/ Submissions: info-performer++at++sgi.com Admin. requests: info-performer-request++at++sgi.com


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:54:06 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.