2013-09-29 35 views
0

我有代碼繼承看起來像這樣:MinGW的4.7.0至4.7.2錯誤:無效「this」指針在成員函數時使用混合虛擬和非虛擬多重繼承

 B 
    /\ 
    / \ 
    / \ 
    BI  D 
(template)/
     \ /
     \/
     DI 
    (template) 

[B]ase[D]erived是包含static方法create()的接口,該方法返回相應實現的實例,即BaseImplDerivedImpl。 實現是模板,工廠方法選擇如何在運行時實例化它們。下面的代碼是我的程序邏輯的一個工作示例。

問題是,在我的真實代碼中,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()調用,其中basestd::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()的調用點處崩潰。

刪除代碼以節省空間。要查看它,請查看編輯歷史記錄。

+0

[C++指針多繼承趣味]的可能的重複(http://stackoverflow.com/questions/2157104/c-pointer-multi-inheritance-fun) –

+1

'this'指針不必停留在在不同派生類中相同。如果你需要最外層對象的基地址,你可以使用'dynamic_cast 'iirc。 –

+0

@AlanStokes是的,你是對的。我發佈的代碼不會重現我在真實代碼中的錯誤。實際代碼中'this'指針的地址超出了程序虛擬內存的範圍,例如。 '0x429bce8'與'0x7a55ec'。我會試着弄清楚發生了什麼。 – hauzer

回答

0

這是一個錯誤。 (55173,55367, 55453)該錯誤特定於gcc-i686-mingw版本4.7.04.7.2

55173

當調用它使用虛擬和非虛擬繼承的對象上的虛擬呼叫,虛擬形實轉換留下一個無效的「this」指針目標函數。

這基本上是我在問題中描述的。應該持有this的註冊表用於非相關操作。

唯一的解決方法是降級到4.7.0以下或升級到4.7.3或以上。