[英]Calling a C++ member function pointer: this-pointer gets corrupted
我需要將一些成員函數指針轉換為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*
和(member)函數指針之間的這種轉換不符合標准,但奇怪的是,當將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
指針隨機調整。
奇怪的是,在這里(在VS2005下),第一次和第三次調用工作正常,但第二次(使用conv3)失敗,因為這被破壞了。
它看起來好像在你的實現上,指向成員函數類型void (test::*) ()
的實例的第一個size(void*)
字節恰好發生,在這種情況下,是內存中函數的地址。 作為一個實現細節,該函數可以調用,就像它是一個自由函數一樣, this
作為第一個參數。 這就是為什么conv3
似乎有效。
但是,當嘗試將第一個sizeof(void*)
字節復制到指向成員函數類型的指針的不同實例時,運氣已經用完。 conv2
的其余部分中的未初始化的垃圾,一旦被解釋為初始代碼地址之后指向成員函數的其余部分,就會出現問題。 我懷疑那里有一些標志和偏移,記錄有關虛函數和多重和虛繼承的信息。 當該信息不正確時,東西出錯了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.