• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            兔子的技術(shù)博客

            兔子

               :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
              202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

            留言簿(10)

            最新評論

            閱讀排行榜

            評論排行榜

            以前知道,在一個(gè)模塊中 new 一塊內(nèi)存,然后在其它模塊中釋放,會導(dǎo)致異常。 但這次出現(xiàn)的問題比較古怪,剛開始根本沒想到是內(nèi)存的原因。
            查找原因比較曲折,但后來用虛函數(shù)的方法解決了問題,沒有修改代碼邏輯,感覺還是比較巧妙的^_^
            執(zhí)行環(huán)境簡單介紹如下:
            一個(gè)靜態(tài)庫工程 MyShare.lib ,關(guān)鍵代碼如下:

             
            // CMyObject 類部分代碼

             
            class CMyObject
             {
             
            public:
                 CMyClient 
            *m_pParent;
                 
            void FinalObject();            
             };
             

            void CMyObject::FinalObject()
            {
                
                m_pParent
            ->UnBand(this);    
                
            }

            // CMyClient 類部分代碼

            class CMyClient
            {
                std::map
            <CMyObject *,int> m_mapObjects;
            public:
                
            void Band(CMyObject *pObject);
                
            void UnBand(CMyObject *pObject);
            };

            void CMyClient::Band(CMyObject *pObject)
            {
                m_mapObjects[pObject] 
            = 1;
            }

            void CMyClient::UnBand(CMyObject *pObject)
            {
                m_mapObjects.erase(pObject);            
            // 這里出現(xiàn)異常!
            }


            一個(gè)引用了 MyShare.lib 的 dll 工程:MyCommon.dll,關(guān)鍵代碼如下
            // 一個(gè)從 CMyObject 派生的類
            class CMyCommonObject : public CMyObject
            {
                
            };

            // 創(chuàng)建一個(gè) CMyCommonObject 
            CMyObject * CreateObject()
            {
                
            return static_cast<CMyObject *>(new CMyCommonObject);
            }

            // 釋放對象
            void ReleaseObject(CMyObject * pObject)
            {
                pObject
            ->FinalObject();
                delete pObject;
            }

            一個(gè)引用了以上兩個(gè)模塊 exe工程:MyTest.exe,關(guān)鍵代碼如下:
            int main(int argc, TCHAR* argv[])
            {
                CMyClient client;

                
            // 調(diào)用 MyCommon.dll 中的代碼創(chuàng)建一個(gè)對象
                CMyObject * pObject = CreateObject();

                
            // 初始化對象
                client.Band(pObject);
                pObject->m_pParent = &client;

                

                
            // 使用完畢,調(diào)用 MyCommon.dll 中的代碼釋放對象
                ReleaseObject(pObject);    
            }

            以上代碼,在運(yùn)行時(shí),會在 m_mapObjects.erase(pObject);  處出現(xiàn)異常;如果單純看類的每個(gè)函數(shù),很難看出問題,另外,工程本身比較復(fù)雜,所以一直沒有懷疑是因?yàn)椴煌K之間分配和釋放內(nèi)存導(dǎo)致的問題。
            值得注意的是,這里的 MyTest.exe 和 MyCommon.dll 中包含了同一個(gè)靜態(tài)庫,也就是說,他們之中都有 CMyObject 和 CMyClient 的二進(jìn)制代碼!很容易向?qū)У氖牵瑔栴}應(yīng)該出在 Band 和 UnBand 。毫無疑問,以上代碼中的 client.Band 執(zhí)行的是 MyTest.exe 中的代碼。那么,m_pParent->UnBand 執(zhí)行的是哪里的代碼呢?之前我想當(dāng)然的以為,既然 m_pParent 指針都是從 MyTest.exe 中傳遞來的,那肯定是執(zhí)行的 MyTest.exe 中的代碼。后來在VC中調(diào)試時(shí)偶然發(fā)現(xiàn),執(zhí)行UnBand 的代碼在 MyCommon.dll  中,才突然想到,調(diào)用類的成員函數(shù)不就相當(dāng)于普通函數(shù)加一個(gè) this 參數(shù)嗎?而普通函數(shù)編譯時(shí)就確定了地址,那肯定是指向自己模塊中的二進(jìn)制代碼了。 那么,m_pParent->UnBand 肯定執(zhí)行的 MyCommon.dll 中的代碼!這樣問題就真相大白了:在 MyTest.exe 中向 map 加入元素,而在 MyCommon.dll  中釋放,肯定會出錯(cuò)!因?yàn)榧尤牖騽h除元素極可能造成堆內(nèi)存分配的變化!

            現(xiàn)在問題找到了,怎么解決呢?如果修改代碼邏輯,則會造成其它關(guān)聯(lián)代碼的修改,想起來都有些頭痛。問題主要是函數(shù)地址,什么函數(shù)是延遲綁定地址的呢?突然想到了虛函數(shù)!從 C++ 機(jī)制我們知道,調(diào)用虛函數(shù)其實(shí)是調(diào)用虛函數(shù)表中的函數(shù)指針,而虛函數(shù)表的內(nèi)容是對象分配的時(shí)候填寫的!那么,這樣就能保證,無論在哪里調(diào)用虛函數(shù),都是調(diào)用分配該對象的模塊中的代碼!

            馬上將 CMyClient 中的 Band 和 UnBand 改成虛函數(shù),再試,問題果然消失了,而且再次用 VC 調(diào)試,發(fā)現(xiàn)從 MyCommon.dll  調(diào)用 UnBand 時(shí) ,也是在MyTest.exe 中執(zhí)行 !^_^
            posted on 2009-09-22 14:29 會飛的兔子 閱讀(452) 評論(2)  編輯 收藏 引用 所屬分類: C++及開發(fā)環(huán)境

            Feedback

            # re: 不同模塊中釋放內(nèi)存出錯(cuò) 2009-09-23 10:55 岳...
            1. 搞的太復(fù)雜了,lib/dll/exe,來回折騰,要共享代碼,要簡單清晰,只用靜態(tài)lib就行,把大量公共代碼重用,這是有多個(gè)模塊時(shí)最好;
            2. dll的使用最好是私密的,不想共享代碼的;這里就會出現(xiàn)模塊分配內(nèi)存的問題;
            3. 在封裝dll時(shí)一定注意2條:
            1. 輸出純虛接口,這樣容易思考,直接隔離;
            2. dll內(nèi)部的內(nèi)存分配與釋放,都在它自己內(nèi)部完成;
            4. C++有很多種方式和技巧,一定要只選一種最簡單最適合自己的思考方式,不要混用,要不然根本沒時(shí)間和精力思考應(yīng)用邏輯,大量時(shí)間消耗在C++本身的技巧上,得不嘗失;

            呵呵。。。。。。。。。
              回復(fù)  更多評論
              

            # re: 不同模塊中釋放內(nèi)存出錯(cuò) 2009-09-23 11:54 會飛的兔子
            回復(fù)老岳:
            很好,有一定道理;
            1條:現(xiàn)在系統(tǒng)必須這樣,又要 lib (有些公共代碼),又要 dll(COM組件)
            2、3條:同意!
            4條:部分同意。我們不能為用技巧而用技巧;當(dāng)程序需要技巧的時(shí)候就用技巧,畢竟‘工欲善其事,必先利其器’嘛,^_^  回復(fù)  更多評論
              

            色老头网站久久网| 狠狠色婷婷久久综合频道日韩| 精品综合久久久久久888蜜芽| 欧美丰满熟妇BBB久久久| 91精品国产乱码久久久久久| 久久国产成人精品麻豆| 久久久精品国产Sm最大网站| 国产成人无码精品久久久性色| 久久夜色精品国产噜噜亚洲AV| 伊人久久大香线蕉影院95| 久久婷婷午色综合夜啪| 97精品伊人久久大香线蕉app| 久久亚洲精品无码观看不卡| 国产精品久久久久无码av| 国产精品久久久久蜜芽| 精品久久综合1区2区3区激情| 国产激情久久久久影院老熟女免费| 久久久久久久久久免免费精品 | 亚洲国产日韩综合久久精品| 久久精品人人做人人爽电影蜜月| 久久久久亚洲精品天堂久久久久久| 久久精品中文字幕无码绿巨人| 久久久久免费视频| 51久久夜色精品国产| 69久久精品无码一区二区| 国产欧美久久久精品影院| 久久精品国产72国产精福利| 久久香蕉国产线看观看乱码| 久久亚洲私人国产精品vA| 久久精品一区二区三区AV| 精品久久久久成人码免费动漫| 久久精品国产亚洲7777| 日韩一区二区久久久久久 | 成人综合久久精品色婷婷| 久久国产福利免费| 久久精品国产精品亚洲艾草网美妙 | 国产69精品久久久久9999APGF | 久久综合九色欧美综合狠狠 | 日本久久久久久久久久| 久久精品这里只有精99品| 国产三级观看久久|