我需要将一些成员函数指针转换为void*
指针(因为我需要将它们压入Lua堆栈,但问题与Lua无关)。
我使用 union
来做到这一点。但是,当我将成员函数指针转换为 void*
并再次返回,然后尝试使用该类的实例调用该指针时,this
指针会损坏。奇怪的是,如果我将 void*
指针转换回 C 风格的函数指针,并将指向该类的指针作为第一个参数,这个问题就不会发生。
这是演示问题的一段代码:
#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;
}
这是输出:
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
这是编译器 (GCC) 中的错误吗?我知道 void*
和(成员)函数指针之间的这种转换不符合标准,但奇怪的是,当将 void*
转换为C 风格的函数指针。
最佳答案
将这两行添加到您的代码中,答案将一目了然:
cout << "sizeof(void*)=" << sizeof(conv1.ptr) << endl;
cout << "sizeof(test::*)=" << sizeof(conv1.func) << endl;
原因很简单。考虑:
class Base1
{
public:
int x;
void Foo();
Base1();
};
class Base2
{
public:
float j;
void Bar();
Base2();
};
class Derived : public Base1, public Base2
{
Derived();
};
当您在 Derived
上调用 Foo
时,this
指针必须指向 Base1::x
。但是当您在 Derived
上调用 Bar
时,this
指针必须指向 Base2::j
!因此,指向成员函数的指针必须包括函数地址和“调整器”,以更正 this
指针指向函数期望的正确类类型的实例 this
指针。
你丢失了调整器,导致 this
指针被随机调整。
关于c++ - 调用C++成员函数指针: this-pointer gets corrupted,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10977388/