我有代碼繼承看起來像這樣:MinGW的4.7.0至4.7.2錯誤:無效「this」指針在成員函數時使用混合虛擬和非虛擬多重繼承
B
/\
/ \
/ \
BI D
(template)/
\ /
\/
DI
(template)
[B]ase
和[D]erived
是包含static
方法create()
的接口,該方法返回相應實現的實例,即BaseImpl
或DerivedImpl
。 實現是模板,工廠方法選擇如何在運行時實例化它們。下面的代碼是我的程序邏輯的一個工作示例。
問題是,在我的真實代碼中,Base
方法得到錯誤的指針並且不可避免地崩潰。我已經研究了彙編代碼調用的方法,它不帶任何參數,在真實和示例代碼一前右,並發現它的不同:
工作(例如)代碼
call <std::unique_ptr<Base, std::default_delete<Base> >::operator->() const>
mov (%eax),%edx
add $0x8,%edx
mov (%edx),%edx
mov %eax,%ecx
call *%edx
以上轉換爲base->method()
調用,其中base
是std::unique_ptr<Base>
。 對於那些不知道的,類方法的調用約定可以是__thiscall,在這種情況下它是。這意味着this
不在堆棧上傳遞,但存儲在ecx
中。上面的代碼只需將this
存儲到ecx
中,然後找到method()
,將其地址存儲到edx
中,然後調用它。一切正常。
故障(實際)代碼
call <std::unique_ptr<Base, std::default_delete<Base> >::operator->() const>
mov (%eax),%edx
add $0x18,%edx
mov (%edx),%ebx
lea -0x24(%ebp),%edx
mov %eax,(%esp)
movl $0x9,-0x9c(%ebp)
mov %edx,%ecx
call *%ebx
這是完全相同的base->method()
通話。 method()
的地址這次存儲在ebx
中。然而,this
是從任意一個地方加載的!正如預期的那樣,該方案崩潰。任何人都知道編譯器爲什麼會生成這樣的程序集?我仍然試圖弄清楚。
代碼
示例代碼如下。真實代碼在類似於示例從invoker->invoke()
到base->check()
的調用點處崩潰。
刪除代碼以節省空間。要查看它,請查看編輯歷史記錄。
[C++指針多繼承趣味]的可能的重複(http://stackoverflow.com/questions/2157104/c-pointer-multi-inheritance-fun) –
'this'指針不必停留在在不同派生類中相同。如果你需要最外層對象的基地址,你可以使用'dynamic_cast'iirc。 –
@AlanStokes是的,你是對的。我發佈的代碼不會重現我在真實代碼中的錯誤。實際代碼中'this'指針的地址超出了程序虛擬內存的範圍,例如。 '0x429bce8'與'0x7a55ec'。我會試着弄清楚發生了什麼。 – hauzer