|
最近的一個項目中遇到了調(diào)用別人的sdk接口(dll庫)而傳給我的是一個vector指針,用完之后還要我來刪除的情況。這個過程中首先就是在我的exe中將其vector指針轉(zhuǎn)為相應(yīng)指針再獲取vector中相應(yīng)的數(shù)據(jù)問題,始終都獲得不了正確的數(shù)據(jù),要么就是一些非法的數(shù)據(jù);另一個問題就是delete這個指針時候會產(chǎn)生相應(yīng)異常(針對這個問題的思考:如果EXE和DLL都鏈接到DLL的C/C++運行期庫,那么代碼將能夠很好地運行.但是,如果兩個模塊中的一個或者兩個鏈接到靜態(tài)C/C++運行期庫,那delete的操作就會失敗.)。這叫一個折騰的糾結(jié)啊 (1)對于STL,在DLL中使用的時候,往往存在這些問題,在網(wǎng)絡(luò)上搜集了下,這些都是要平時使用STL的時候注意的。 template 是個好東西啊 . 經(jīng)典的 stl . 強悍的boost. 還有我自己寫的那個 ------- 該死的 ------- 資源管理器.dynamic link也是個好東西啊. 在windows下叫dll, 在unix下叫so (share object) . 它能省下很多重新發(fā)布軟件帶來的麻煩.但是當(dāng)template 遭遇到dynamic link 時候, 很多時候卻是一場惡夢.現(xiàn)在來說說一部分我已經(jīng)碰到過的問題. 問題主要集中在內(nèi)存分配上.
1> 拿STL來說, 自己寫模板的時候,很難免就用到stl. stl的代碼都在頭文件里. 那么表示著內(nèi)存分配的代碼.只有包含了它的cpp 編譯的時候才會被決定是使用什么樣的內(nèi)存分配代碼. 考慮一下: 當(dāng)你聲明了一個vector<> . 并把這個vector<>交給一個 dll里的代碼來用. 用完后, 在你的程序里被釋放了. 那么如果你 在dll里往vector里insert了一些東西. 那么這個時候insert 發(fā)生的內(nèi)存分配的代碼是屬于dll的. 你不知道這個dll的內(nèi)存分配是什么. 是分配在哪里的. 而這個時候.釋放那促的動作卻不在dll里.....同時. 你甚至無法保證編譯dll的那個家伙使用的stl版本和你是完全一樣的..> 如此說來, 程序crash掉是天經(jīng)地義的.... 對策: 千萬別別把你的stl 容器,模板容器在 dll 間傳來傳去 . 記住string也是....
2> 你在dll的某個類里聲明了一個vector之類的容器. 而沒有顯式的寫這個類的構(gòu)造和析構(gòu)函數(shù). 那么問題又來了. 你這個類肯定有操作這vector的函數(shù). 那么這些函數(shù)會讓vecoter<>生成代碼. 這些代碼在這個dll里都是一致的. 但是別忘了.你沒有寫析構(gòu)函數(shù)...... 如果這個時候, 別人在外面聲明了一個這樣的類.然后調(diào)用這個類的函數(shù)操作了這個vector( 當(dāng)然使用者并不知道什么時候操作了vector) . 它用完了這個類以后. 類被釋放掉了. 編譯器很負責(zé)的為它生成了一份析構(gòu)函數(shù)的代碼...... 聽好了.這份代碼并不是在 dll里 ... . 事情于是又和1>里的一樣了.... crash ......(可能還會伴隨著迷茫.....) 對策: 記得dll里每個類,哪怕式構(gòu)造析構(gòu)函數(shù)式空的. 也要寫到cpp里去. 什么都不寫也式很糟糕的.....同時,更要把任何和內(nèi)存操作有關(guān)的函數(shù)寫到 .cpp 里...
3> 以上兩個問題似乎都是比較容易的-----只要把代碼都寫到cpp里去, 不要用stl容器傳來傳去就可以了. 那么第三個問題就要麻煩的多. 如果你自己寫了一個模板, 這個模板用了stl 容器.......... 這個時候你該怎么辦呢? 顯然你無法把和內(nèi)存分配相關(guān)的函數(shù)都寫到.cpp里去 . template的代碼都必須放到header file里..... 對策: 解決這個問題的基本做法是做一個stl 內(nèi)存分配器 , 強制把這個模板里和內(nèi)存分配相關(guān)的放到一個.cpp里去.這個時候編譯這個cpp就會把內(nèi)存分配代碼固定在一個地方: 要么是dll. 要么是exe里... 模板+動態(tài)鏈接庫的使用問題還很多. 要千萬留心這個陷阱遍地的東西啊
另外,對於這種問題的解決辦法,下面3種可行辦法:
1. 傳遞vector指針【注意:事實證明,這個也是不行的】
2. 傳遞const vector
3. 儘量不使用stl作為dll間的傳遞參數(shù),使用指針會更好點
究其原因:是因為vector在exe和dll之間傳遞的時候,由于在dll內(nèi)可能對vector插入數(shù)據(jù),而這段內(nèi)存是在dll里面分配的,exe無法知道如何釋放內(nèi)存,從而導(dǎo)致問題。而改成const類型后,編譯器便知道dll里不會改變vector,從而不會出錯?;蛘呖梢哉f這是"cross-DLL problem."(This problem crops up when an object is created using new in one dynamically linked library (DLL) but is deleted in a different DLL)的一種吧。
(2) 從一個可執(zhí)行程序中輸出模板實例,在另一個可執(zhí)行程序中引入此實例。例如:MyLibrary.DLL將vector <MyClass> 指針回傳給MyProgram.EXE中的一個函數(shù),需要在MyLibrary.DLL中輸出MyClass類和vector <MyClass> 。在MyProgram.EXE中引入它們后。就可以得到MyLibrary.DLL中靜態(tài)數(shù)據(jù)成員的一份Copy了。 這個是解決我這個問題的挺不錯的方法,但是并為給予采納和驗證。畢竟為了保險起見最終還是選擇了數(shù)組傳遞數(shù)據(jù),但是還是要給予的原則是誰創(chuàng)建誰釋放。否則還是會出問題我這里即便是調(diào)用delete[ ]objArray;這里的delete的并不知道要刪除多大的內(nèi)存,而這個要刪除多大的內(nèi)存信息是在dll中保存著的,那個dll中的delete才知道。DLL中分配的內(nèi)存DLL要負責(zé)釋放?。ㄒ粋€模塊分配的內(nèi)存要在同一個模塊中釋放?。?/span>
*************************************************************************************************************************** 微軟關(guān)于這類問題的解釋: You may experience an access violation when you access an STL object through a pointer or reference in a different DLL or EXE http://support.microsoft.com/default.aspx?scid=KB;en-us;q172396 How to export an instantiation of a Standard Template Library (STL) class and a class that contains a data member that is an STL object http://support.microsoft.com/default.aspx?scid=KB;en-us;q168958
這個講解也不錯:http://blog.csdn.net/lewutian/article/details/6786193
STL跨平臺調(diào)用會出現(xiàn)很多異常,你可以試試.
STL使用模板生成,當(dāng)我們使用模板的時候,每一個EXE,和DLL都在編譯器產(chǎn)生了自己的代碼,導(dǎo)致模板所使用的靜態(tài)成員不同步,所以出現(xiàn)數(shù)據(jù)傳遞的各種問題,下面是詳細解釋。
原因分析:
在動態(tài)連接庫開發(fā)中要特別注意內(nèi)存的分配與釋放問題,稍不注意,極可能造成內(nèi)存泄漏,從而訪問出錯。例如在某DLL中存在這樣一段代碼:
|
|
|