處理了一個_CrtIsValidHeapPointer的問題

在dll中創建了一個QDialog,但是考慮到風格優化,就給DLL關聯了風格優化的Style模塊,從而可以引用StyleDialog類來提供產品統一風格。但是關閉Dialog的時候出現錯誤

 

單步跟蹤發現是原窗體釋放之後進入到: `scalar deleting destructor' 語句時候出現堆異常。並且彈出斷言錯誤窗口,提示_CrtIsValidHeapPointer,看名字也是和堆指針有關係的一個問題。

 

探索原因:應該是直接把DLL裏的子類QDialog作爲child成員掛到了風格窗體下,並且都是以對象的方式存在,因此釋放的時候直接在StyleDialog的釋放流程中析構對象,由於這個類的對象不在堆上,就出現了問題。

 

解決方法:把對象替換爲指針新建,就不再報錯。指針自己維護其釋放即可。

{

    GBQNewForm *pNewForm = new GBQNewForm();    // 使用指針而不是對象

    StyleDialog oStyleDlg;

    oStyleDlg.dialogExec();

    freeAndNil(pNewForm);    // 自己管理指針的釋放

}

這裏需要關注一下,警惕靜態鏈接情況下,另一個模塊的對象下掛本模塊生成的對象並在析構時候自動析構對象。(Qt直接通過pro文件把另一個模塊引入過來就是靜態鏈接了)

 

 

引用其他文章:原文鏈接:https://blog.csdn.net/linfengmove/article/details/83151932

跨模塊傳遞C++對象,如果大家共用C++動態庫,沒有關係,因爲在調用結束,棧上的函數參數析構後清除同一C++庫管理的內存,但是如果是靜態鏈接的C++動態庫,那就麻煩了,會導致申請在一個模塊中,釋放在另一個模塊中(這塊一會介紹下)。大家用的不是同一個堆內存,釋放的內存對象就不對了。這種情況下就使用基本類型(int, char, 指針等),這樣就避免了申請和釋放內存的問題。

 

C++在跨模塊調用函數時,如果參數是C++類,那麼會在被調用方的棧上申請內存,但是函數調用完畢後,要釋放參數的空間則是使用調用方的清除函數,所以就造成了申請和釋放內存的不匹配。

 

      __cdecl調用方式(C++默認調用方式),參數由調用者釋放,所以跨dll傳遞的C++類型參數,棧內存是由被調用者申請的,但是釋放是由調用者來進行,兩個模塊如果是動態鏈接的C++庫,那麼這個沒有問題,因爲大家釋放的都是同一個C++運行庫中的堆棧地址,如果不是那就會造成程序錯誤。

 

      __stdcall調用方式,參數由被調用者申請內存,釋放也是由被調用者釋放,所以大家都在同一個C++運行期庫中申請/釋放,所以不會有問題。但是事實在驗證中還是出了問題,函數調用不返回。

 

所以,在跨模塊傳遞參數的時候,要不選擇基礎類型,要不就直接傳遞指針(內存由調用者管理),避免在跨模塊造成的內存管理問題。另外儘量選擇動態鏈接到C++運行期庫,這樣內存管理更安全。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章