I need to convert some member function pointers to void*
pointers (because I need to push them to the Lua stack, but the problem is not Lua related).
I do this using a union
. But when I convert the member function pointers to a void*
and back again and then try to call the pointer with an instance of the class, the this
pointer gets corrupted. Strangly, this problem doesn't happen, if I convert the void*
pointer back into a C-style function pointer with a pointer to the class as it's first parameter.
Here is piece of code that demonstrates the problem:
#include <iostream>
using namespace std;
class test
{
int a;
public:
void tellSomething ()
{
cout << "this: " << this << endl;
cout << "referencing member variable..." << endl;
cout << a << endl;
}
};
int main ()
{
union
{
void *ptr;
void (test::*func) ();
} conv1, conv2;
union
{
void *ptr;
void (*func) (test*);
} conv3;
test &t = *new test ();
cout << "created instance: " << (void*) &t << endl;
// assign the member function pointer to the first union
conv1.func = &test::tellSomething;
// copy the void* pointers
conv2.ptr = conv3.ptr = conv1.ptr;
// call without conversion
void (test::*func1) () = conv1.func;
(t.*func1) (); // --> works
// call with C style function pointer invocation
void (*func3) (test*) = conv3.func;
(*func3) (&t); // --> works (although obviously the wrong type of pointer)
// call with C++ style member function pointer invocation
void (test::*func2) () = conv2.func;
(t.*func2) (); // `this' is the wrong pointer; program will crash in the member function
return 0;
}
That is the output:
created instance: 0x1ff6010
this: 0x1ff6010
referencing member variable...
0
this: 0x1ff6010
referencing member variable...
0
this: 0x10200600f
referencing member variable...
zsh: segmentation fault (core dumped) ./a.out
Is this a bug in the compiler (GCC)? I know that this conversion between void*
and (member) function pointers is not standard compliant, but the odd thing is, that it works, when converting the void*
to a C style function pointer.
You can use pointers to member functions in the same manner as pointers to functions. You can compare pointers to member functions, assign values to them, and use them to call member functions.
There are two main issues with function pointers: Function pointer casts can cause function pointer calls to fail. This may be related to a function pointer cast problem as implicit declarations may have a different type than how you call them.
The this pointer is a pointer accessible only within the nonstatic member functions of a class , struct , or union type. It points to the object for which the member function is called. Static member functions don't have a this pointer.
A static member function does not have a this pointer. The type of the this pointer for a member function of a class type X , is X* const .
Add these two lines to your code and the answer will be clear:
cout << "sizeof(void*)=" << sizeof(conv1.ptr) << endl;
cout << "sizeof(test::*)=" << sizeof(conv1.func) << endl;
The reason is simple. Consider:
class Base1
{
public:
int x;
void Foo();
Base1();
};
class Base2
{
public:
float j;
void Bar();
Base2();
};
class Derived : public Base1, public Base2
{
Derived();
};
When you call Foo
on a Derived
, the this
pointer must point to Base1::x
. But when you call Bar
on a Derived
, the this
pointer must point to Base2::j
! So a pointer to a member function must include both the address of the function and an "adjustor" to correct the this
pointer to point to an instance of the correct type of class that the function expects as the this
pointer.
You are losing the adjuster, causing the this
pointer to be adjusted randomly.
Weirdly enough, here (under VS2005), the 1st and 3rd calls works fine but the 2nd (with conv3) fails with the this being corrupted.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With