• <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>

            focus on linux, c/c++, lua

            被delete難倒了

            話說我有一個結構體如下:
            struct stReplayData
            {
                
            int nDelay;        // 該數據在上一條消息之后的延遲,仿真(目前自定義1秒鐘)
                char* pData;    // 網絡數據包的內容
                int nLen;        // 長度

                stReplayData()
                
            {
                    nDelay 
            = 0;
                    nLen 
            = 0;
                    pData 
            = NULL;
                }


                stReplayData(
            int nLength)
                
            {
                    nDelay 
            = 0;
                    nLen 
            = nLength;
                    pData 
            = NULL;
                    
            if (nLen > 0)
                    
            {
                        pData 
            = new char[nLen];
                    }
                            
                }


                stReplayData(
            const stReplayData& src)
                
            {
                    
            if (this == &src)
                    
            {
                        
            return;
                    }

                    
            *this = src;
                }


                stReplayData
            & operator = (const stReplayData& src)
                
            {
                    
            if (this == &src)
                    
            {
                        
            return *this;
                    }

                    nDelay 
            = src.nDelay;
                    
            if (pData != NULL)
                    
            {
                        delete[] pData;
                        pData 
            = NULL;
                    }
                    
                    nLen 
            = src.nLen;
                    
            if (nLen > 0)
                    
            {
                        pData 
            = new char[nLen];        
                        memcpy(pData, src.pData, nLen);
                    }

                    
            return *this;
                }


                
            ~stReplayData()
                
            {
                    nDelay 
            = 0;
                    nLen 
            = 0;
                    
            if (pData != NULL)
                    
            {
                        delete[] pData;            
                        pData 
            = NULL;
                    }
                    
                }

            }
            ;

            我定義了一個vector<stReplayData*> m_vecReplay,然后new了一些stReplayData ,push_back這些指針進去,最后程序釋放資源的時候,居然報調用釋放指針出錯了,報的錯就是平時見的很多的Heap上指針無效的錯誤,基本上是說stReplayData的析構函數有問題,我了個擦,我怎么沒看出哪里有問題呢?

            =====================================更多的代碼如下===============================================
            我封裝了一個dll作為一個公共模塊,自然數據都會在這個公共模塊中存儲,其中內存數據的管理也會在這個dll中去做,也就是說,new和delete都會由這個dll自己去管理,
            使用者只要去調接口,然后把需要存儲的數據地址傳給dll,讓dll自己去拷貝即可。模塊其實非常簡單:
            class CReplayManager : public IReplayManager
            {
                typedef vector
            <stReplayData*> VECREPLAY;
            public:
                CReplayManager();
                
            virtual ~CReplayManager();
                
            virtual bool PushData(stReplayData* pData);
                
            virtual stReplayData* PopData();
                
            virtual stReplayData* GetTailData();
                
            virtual void ClearData();
                
            virtual void Release();    
            private:
                VECREPLAY m_vecReplay;
            }
            ;
            這里還有個模版函數,讓主程序朝dll寫數據,
            template<class M, class T>
            void WriteReplay(M* m, const T& t)
            {
                CWrite cw;
                cw.Write(t);
                stReplayData
            * pReplay = new stReplayData(cw.GetLen());
                
            if (pReplay != NULL)
                
            {        
                    pReplay
            ->nLen = cw.GetLen();
                    memcpy(pReplay
            ->pData, cw.GetData(), cw.GetLen());
                    m
            ->PushData(pReplay);
                }
                    
            }
            另:在主程序里單獨的操作stReplayData是沒什么問題的,我也試驗過。

            =================================總結=================================
            re: 被delete難倒了 2011-03-31 11:49 dizhu

            問題就是SAFE_DELETE((*it)); 這個是在exe中new的,不能在dll中delete。

            深入:
            如果一個EXE調用一個DLL時,用new和delete分配和釋放內存為什么應該放在同一個背景下的原因。得出的結論是,如果EXE和DLL有一個不是用動態鏈接CRT庫(C   runtime   library)的方式使用CRT的話(Multi-threaded Debug DLL (/MDd)),或者是EXE和DLL動態鏈接的CRT庫的版本不同時,EXE和DLL將會各自擁有各自的堆空間,所以在DLL中new的東西務必在DLL中delete。

            posted on 2011-03-30 17:29 zuhd 閱讀(2189) 評論(29)  編輯 收藏 引用 所屬分類: c/c++

            評論

            # re: 被delete難倒了 2011-03-30 17:36 namelij

            你去看看vector里面的對象是怎么釋放的,就明白了  回復  更多評論   

            # re: 被delete難倒了 2011-03-30 17:46 dizhu

            貼下完整的代碼  回復  更多評論   

            # re: 被delete難倒了 2011-03-30 17:50 Kevin Lynx

            @dizhu
            問題確實可能出在其他地方。  回復  更多評論   

            # re: 被delete難倒了 2011-03-30 17:55 千暮(zblc)

            我按你說的做了一遍 沒有報錯 - -bnr 你咋不把調用的代碼發下  回復  更多評論   

            # re: 被delete難倒了[未登錄] 2011-03-30 20:58 vincent

            應該還是也指著啊  回復  更多評論   

            # re: 被delete難倒了[未登錄] 2011-03-30 20:59 vincent

            野指針……  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 00:50 Mensch88

            1. 就這段代碼本身來說,有一個錯誤:拷貝構造函數 stReplayData(const stReplayData& src) 里的指針pData沒有初始化!

            2.stReplayData的析構函數本身沒有問題。程序報錯應該是調用了兩次析構函數造成的。
            比如說,很有可能在使用時會犯這樣的錯誤:
            stReplayData data(otherdata);
            vec.push_back(&data);
            由于data本身會調用析構函數delete pData,而delete vec里面的數據時也會調用data的析構函數,于是掛了。

              回復  更多評論   

            # re: 被delete難倒了 2011-03-31 01:13 Mensch88

            不好意思,第二點我說得不大對,因為樓主在析構函數里判斷了 if (pData != NULL), 并且之后會把pData=NULL,所以調用兩次析構在單線程環境里不會問題。當然多線程環境下就另說了。

            但我所陳述的問題依然是存在的,只是這不是因為兩次析構造成,而是因為data是棧上的數據,不允許delete,所以掛了。  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 09:14 zuhd

            @Mensch88
            1. 就這段代碼本身來說,有一個錯誤:拷貝構造函數 stReplayData(const stReplayData& src) 里的指針pData沒有初始化!

            拷貝構造函數是調用operator =來著  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 09:36 dizhu

            @Mensch88
            vector里面保存的是指針,不會調用delete 的,不會存在你說的兩次析構函數調用  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 09:39 dizhu

            @dizhu
            如果樓主
            stReplayData data(otherdata);
            vec.push_back(&data);
            然后還去delete vec里面的數據,那就是樓主代碼寫的有問題,所以說還是貼下完整的代碼,才能知道問題。但就這個stReplayData,還真看不出為什么會掛  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 10:13 zuhd

            我更新了帖子 貼了更多的代碼 想嘗試的朋友 可以自己簡單修改下即可  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 11:13 zuhd

            問題我找到了,是我以前遇到的老問題
            virtual bool PushData(stReplayData* pData);
            這個接口設計有問題,dll的接口應該用標準的c++類型,我只知道其然,不知道所以然,了解詳情的說下  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 11:17 dizhu

            @zuhd
            重點把delete stReplayData 的代碼 和 CReplayManager 貼出來看下  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 11:22 zuhd

            @dizhu
            看了頭文件基本就能猜到代碼了吧 中規中矩的容器操作代碼而已

            另:我在gcc中的頭文件大量的使用了自定義的類,貌似沒發現過什么問題,怎么用vc上來就碰到這個,是巧合還是必然?腫么辦?有沒有,有沒有?  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 11:24 dizhu

            @zuhd
            我比較關心CReplayManager 的Release 以及 ClearData 的實現。是不是在這里面delete stReplayData 了??  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 11:41 zuhd

            void CReplayManager::ClearData()
            {
            VECREPLAY::iterator it = m_vecReplay.begin();
            for (; it != m_vecReplay.end(); it++)
            {
            SAFE_DELETE((*it));
            }
            m_vecReplay.clear();
            }  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 11:49 dizhu

            @zuhd
            void CReplayManager::ClearData()
            {
            VECREPLAY::iterator it = m_vecReplay.begin();
            for (; it != m_vecReplay.end(); it++)
            {
            SAFE_DELETE((*it));
            }
            m_vecReplay.clear();
            }
            問題就是SAFE_DELETE((*it)); 這個是在exe中new的,不能在dll中delete。
            原因:http://blog.csdn.net/blz_wowar/archive/2008/03/13/2176536.aspx  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 11:56 zuhd

            @dizhu
            在exe中new,不能在dll中delete的?
            exe和dll用的是同一個堆棧空間的,  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 17:48 Mensch88

            zuhd@zuhd
            --拷貝構造函數是調用operator =來著

            拷貝構造函數是調用了operator=,但是operator=里面會判斷pData是否為NULL:
            if (pData != NULL)
            {
            delete[] pData;
            pData = NULL;
            }
            必須注意的是,這時pData還沒有被初始化。這樣就會執行 delete[] pData;
            從而出錯。  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 17:55 Mensch88

            @dizhu
            --然后還去delete vec里面的數據,那就是樓主代碼寫的有問題,所以說還是貼下完整的代碼,才能知道問題。但就這個stReplayData,還真看不出為什么會掛

            因為樓主說了vec里面是一些new出來的指針,而之后程序釋放資源時報錯,于是我估計樓主所說的程序釋放資源就是指將vec里面的指針delete。
            樓主后來的代碼也證實了我的猜測。

              回復  更多評論   

            # re: 被delete難倒了 2011-03-31 18:31 Mensch88

            樓主的問題算是CRT的bug么?
            Linux下測試,無論是靜態還是動態鏈接都沒發現這種問題。  回復  更多評論   

            # re: 被delete難倒了 2011-03-31 23:54 flyinghearts


            建議還是用 vector<char> 或 string 代替 char*

            stReplayData 設計得有點問題,
            一般都是 在拷貝構造函數中進行分配新內存處理, 然后在賦值函數中調用拷貝構造函數,構造一個臨時類對像,與原類對象進行交換。

            你的實現剛好相反,拷貝構造函數調用 賦值函數,但 賦值函數中用到的 nlen 和 pdata兩個值都未初始化,UB行為。

            實際上,這兩個判斷都是可以去掉的,new char[0] 是有意義的,沒必要對 nlen進行判斷
            delete[] p 當p是空指針時,沒有任何效果,因此沒必要對pdata進行判斷

            拷貝構造函數中 對指針的判斷 也是多余的。
            另外,要先分配新內存,再釋放舊內存,保證 異常安全。

              回復  更多評論   

            # re: 被delete難倒了 2011-04-01 09:44 zuhd

            @flyinghearts
            那個拷貝構造函數確實有點問題,以前拷貝構造函數調用=寫順手了,沒發現有內存操作的這么寫有這個陷阱,改了一下:
            stReplayData(const stReplayData& src)
            {
            if (this == &src)
            {
            return;
            }
            nDelay = src.nDelay;
            nLen = src.nLen;
            pData = new char[nLen];
            if (pData != NULL)
            {
            memcpy(pData, src.pData, nLen);
            }
            }

            stReplayData& operator = (const stReplayData& src)
            {
            if (this == &src)
            {
            return *this;
            }
            nDelay = src.nDelay;
            nLen = src.nLen;
            if (pData != NULL)
            {
            delete[] pData;
            pData = NULL;
            }
            pData = new char[nLen];
            if (pData != NULL)
            {
            memcpy(pData, src.pData, nLen);
            }
            return *this;
            }

            至于你說的:
            另外,要先分配新內存,再釋放舊內存,保證 異常安全。
            好像我一直都是先delete 再new ,可能一直懶得用個臨時的指針來保存pData吧,不過你這么說的道理是??  回復  更多評論   

            # re: 被delete難倒了[未登錄] 2011-04-01 11:32 hdqqq

            如果樓主使用 /mt 編譯,dll啟動時使用自己的堆, 在主程序中new 出來的對象,再通過指針傳給dll,然后在dll中釋放,會產生錯誤,主程序和dll使用不同的堆。  回復  更多評論   

            # re: 被delete難倒了[未登錄] 2011-04-01 14:39 楊粼波

            把struct改為class,然后把數據private,測試一次看看。排除客戶代碼應用上的錯誤。

            當然了,也有可能在調用的時候,被其他地方的錯誤牽連導致這個struct的數據被損壞。

            如果牽扯到DLL的話,那有可能是exe和dll兩者之間的版本不一致所導致,DLL的導出地址是用的一個,卻不想exe用了另外一個,所以發生錯誤,這是有可能發生的。用VS的編譯器,特別是2003,你需要依照以下步驟重編譯:清理全部(包括dll和exe)->重編。  回復  更多評論   

            # re: 被delete難倒了[未登錄] 2011-04-01 15:40 楊粼波

            http://blog.csdn.net/ssli/archive/2009/06/16/4272484.aspx  回復  更多評論   

            # re: 被delete難倒了 2011-04-01 23:30 flyinghearts

             
            class stReplayData
            {
              
            int nDelay;     // 該數據在上一條消息之后的延遲,仿真(目前自定義1秒鐘)
              size_t nLen;  // 長度
              char* pData;    // 網絡數據包的內容
              
            public:  
              stReplayData(size_t nLength 
            = 0): nDelay(0), 
                  nLen(nLength), pData(
            new char[nLength]()) {}
              
              
            ~stReplayData() { delete[] pData; }
              
              stReplayData(
            const stReplayData& src):  nDelay(src.nDelay),
                  nLen(src.nLen), pData(
            new char[src.nLen]) 
              {
                memcpy(pData, src.pData, nLen);  
              }
                
              stReplayData
            & operator=(stReplayData tmp) //構建一個臨時對像
              {
                nDelay 
            = tmp.nDelay;
                nLen 
            = tmp.nLen;
                std::swap(pData, tmp.pData);
                
            return *this;
              }
            };

             
            可參考以前寫的這篇文章:
            http://blog.csdn.net/flyinghearts/archive/2010/06/16/5673089.aspx
              回復  更多評論   

            # re: 被delete難倒了 2011-04-02 11:42 tingya

            涉及到跨模塊內存使用的問題,應該遵守誰使用,誰釋放  回復  更多評論   

            狠狠人妻久久久久久综合| 日产精品久久久久久久性色| 日产精品久久久久久久| 久久久久黑人强伦姧人妻| 伊人久久大香线蕉影院95| 久久99精品综合国产首页| 97久久久久人妻精品专区| 欧洲成人午夜精品无码区久久| 97精品依人久久久大香线蕉97 | 91麻精品国产91久久久久| 国产精品美女久久久m| 久久国产精品一区二区| 日本久久久久久中文字幕| 精品久久久久久99人妻| 日韩十八禁一区二区久久| 精品伊人久久久| 国产精品一久久香蕉国产线看| 日产精品久久久一区二区| 久久久91精品国产一区二区三区| 色综合合久久天天综合绕视看| 香蕉久久一区二区不卡无毒影院| 久久精品国产99久久香蕉| 久久精品中文无码资源站| 精品久久久久久国产潘金莲| 国产精品久久久天天影视香蕉 | 狠狠久久亚洲欧美专区| 婷婷久久综合九色综合98| 四虎影视久久久免费观看| 一本色道久久88—综合亚洲精品| 久久人人爽人人爽人人片av高请 | 9999国产精品欧美久久久久久| 久久久久99精品成人片| 亚洲人成精品久久久久| Xx性欧美肥妇精品久久久久久| 国产精品久久久久久久人人看| 国产国产成人精品久久| 午夜精品久久久久久久无码| 国产亚洲精久久久久久无码| 久久久久99这里有精品10| 国内精品久久九九国产精品| 精品国产乱码久久久久软件|